解析 XML 中关于 dataSource 数据源信息配置,并建立事务管理和连接池的启动和使用,并将这部分能力在 DefaultSqlSession 执行 SQL 语句时进行调用。
怎么完成对数据源的解析?
pom.xml
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.48version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.9version>
dependency>
dependencies>
mybatis-step-04
|-src
|-main
| |-java
| |-com.lino.mybatis
| |-binding
| | |-MapperMethod.java
| | |-MapperProxy.java
| | |-MapperProxyFactory.java
| | |-MapperRegistry.java
| |-builder
| | |-xml
| | | |-XMLConfigBuilder.java
| | |-BaseBuilder.java
| |-datasource
| | |-druid
| | | |-DruidDataSourceFacroty.java
| | |-DataSourceFactory.java
| |-io
| | |-Resources.java
| |-mapping
| | |-BoundSql.java
| | |-Environment.java
| | |-MappedStatement.java
| | |-ParameterMapping.java
| | |-SqlCommandType.java
| |-session
| | |-defaults
| | | |-DefaultSqlSession.java
| | | |-DefaultSqlSessionFactory.java
| | |-Configuration.java
| | |-SqlSession.java
| | |-SqlSessionFactory.java
| | |-SqlSessionFactoryBuilder.java
| | |-TransactionIsolationLevel.java
| |-transaction
| | |-jdbc
| | | |-JdbcTransaction.java
| | | |-JdbcTransactionFactory.java
| | |-Transaction.java
| | |-TransactionFactory.java
| |-type
| | |-JdbcType.java
| | |-TypeAliasRegistry.java
|-test
|-java
| |-com.lino.mybatis.test
| |-dao
| | |-IUserDao.java
| |-po
| | |-User.java
| |-ApiTest.java
|-resources
|-mapper
| |-User_Mapper.xml
|-mybatis-config-datasource.xml
一次数据库的操作应该具备事务管理能力,而不是通过 JDBC 获取链接后直接执行,还应该把控链接、提交、回滚和关闭的操作处理。结合 JDBC 的能力封装事务管理。
TransactionIsolationLevel.java
package com.lino.mybatis.session;
import java.sql.Connection;
/**
* @description: 事务的隔离级别
*/
public enum TransactionIsolationLevel {
//包括JDBC支持的5个级别
NONE(Connection.TRANSACTION_NONE),
READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);
private final int level;
TransactionIsolationLevel(int level) {
this.level = level;
}
public int getLevel() {
return level;
}
}
Transaction.java
package com.lino.mybatis.transaction;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @description: 事务接口
*/
public interface Transaction {
/**
* 获取数据库连接
*
* @return 数据库连接
* @throws SQLException SQL异常
*/
Connection getConnection() throws SQLException;
/**
* 提交
*
* @throws SQLException SQL异常
*/
void commit() throws SQLException;
/**
* 回滚
*
* @throws SQLException SQL异常
*/
void rollback() throws SQLException;
/**
* 关闭
*
* @throws SQLException SQL异常
*/
void close() throws SQLException;
}
JdbcTransaction.java
package com.lino.mybatis.transaction.jdbc;
import com.lino.mybatis.session.TransactionIsolationLevel;
import com.lino.mybatis.transaction.Transaction;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @description: JDBC 事务,直接利用 JDBC 的commit、rollback。依赖于数据源获得的连接管理事务范围
*/
public class JdbcTransaction implements Transaction {
protected Connection connection;
protected DataSource dataSource;
protected TransactionIsolationLevel level = TransactionIsolationLevel.NONE;
protected boolean autoCommit;
public JdbcTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
this.dataSource = dataSource;
this.level = level;
this.autoCommit = autoCommit;
}
public JdbcTransaction(Connection connection) {
this.connection = connection;
}
@Override
public Connection getConnection() throws SQLException {
connection = dataSource.getConnection();
connection.setTransactionIsolation(level.getLevel());
connection.setAutoCommit(autoCommit);
return connection;
}
@Override
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
connection.commit();
}
}
@Override
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
connection.rollback();
}
}
@Override
public void close() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
connection.close();
}
}
}
TransactionFactory.java
package com.lino.mybatis.transaction;
import com.lino.mybatis.session.TransactionIsolationLevel;
import javax.sql.DataSource;
import java.sql.Connection;
/**
* @description: 事务工厂
*/
public interface TransactionFactory {
/**
* 根据 Connection 创建 事务
*
* @param conn 连接
* @return 事务对象
*/
Transaction newTransaction(Connection conn);
/**
* 根据数据源和事务隔离级别创建事务
*
* @param dataSource 数据源
* @param level 事务隔离级别
* @param autoCommit 是否自动提交
* @return 事务
*/
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
JdbcTransactionFactory.java
package com.lino.mybatis.transaction.jdbc;
import com.lino.mybatis.session.TransactionIsolationLevel;
import com.lino.mybatis.transaction.Transaction;
import com.lino.mybatis.transaction.TransactionFactory;
import javax.sql.DataSource;
import java.sql.Connection;
/**
* @description: JDBC 事务工厂
*/
public class JdbcTransactionFactory implements TransactionFactory {
@Override
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
@Override
public Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(dataSource, level, autoCommit);
}
}
DataSourceFactory.java
package com.lino.mybatis.datasource;
import javax.sql.DataSource;
import java.util.Properties;
/**
* @description: 数据源工厂
*/
public interface DataSourceFactory {
/**
* 添加数据源
*
* @param props 数据源信息
*/
void setProperties(Properties props);
/**
* 获取数据源
*
* @return 数据源
*/
DataSource getDataSource();
}
DruidDataSourceFactory.java
package com.lino.mybatis.datasource.druid;
import com.alibaba.druid.pool.DruidDataSource;
import com.lino.mybatis.datasource.DataSourceFactory;
import javax.sql.DataSource;
import java.util.Properties;
/**
* @description: Druid 数据源工厂
*/
public class DruidDataSourceFactory implements DataSourceFactory {
private Properties props;
@Override
public void setProperties(Properties props) {
this.props = props;
}
@Override
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(props.getProperty("driver"));
dataSource.setUrl(props.getProperty("url"));
dataSource.setUsername(props.getProperty("username"));
dataSource.setPassword(props.getProperty("password"));
return dataSource;
}
}
BoundSql.java
package com.lino.mybatis.mapping;
import java.util.Map;
/**
* @description: 绑定的SQL,是从SqlSource而来,将动态内容都处理完成得到的SQL语句字符串,其中包括?,还有绑定的参数
*/
public class BoundSql {
private String sql;
private Map<Integer, String> parameterMappings;
private String parameterType;
private String resultType;
public BoundSql(String sql, Map<Integer, String> parameterMappings, String parameterType, String resultType) {
this.sql = sql;
this.parameterMappings = parameterMappings;
this.parameterType = parameterType;
this.resultType = resultType;
}
public String getSql() {
return sql;
}
public Map<Integer, String> getParameterMappings() {
return parameterMappings;
}
public String getParameterType() {
return parameterType;
}
public String getResultType() {
return resultType;
}
}
ParameterMapping.java
package com.lino.mybatis.mapping;
import cn.hutool.db.meta.JdbcType;
import com.lino.mybatis.session.Configuration;
/**
* @description: 参数映射 #{property,javaType=int,jdbcType=NUMERIC}
*/
public class ParameterMapping {
private Configuration configuration;
/**
* property
*/
private String property;
/**
* javaType = int
*/
private Class<?> javaType = Object.class;
/**
* javaType = NUMERIC
*/
private JdbcType jdbcType;
public ParameterMapping() {
}
public static class Builder {
private ParameterMapping parameterMapping = new ParameterMapping();
private Builder(Configuration configuration, String property) {
parameterMapping.configuration = configuration;
parameterMapping.property = property;
}
public Builder javaType(Class<?> javaType) {
parameterMapping.javaType = javaType;
return this;
}
public Builder jdbcType(JdbcType jdbcType) {
parameterMapping.jdbcType = jdbcType;
return this;
}
}
public Configuration getConfiguration() {
return configuration;
}
public String getProperty() {
return property;
}
public Class<?> getJavaType() {
return javaType;
}
public JdbcType getJdbcType() {
return jdbcType;
}
}
Environment.java
package com.lino.mybatis.mapping;
import com.lino.mybatis.transaction.TransactionFactory;
import javax.sql.DataSource;
/**
* @description: 环境
*/
public final class Environment {
/**
* 环境id
*/
private final String id;
/**
* 事务工厂
*/
private final TransactionFactory transactionFactory;
/**
* 数据源
*/
private final DataSource dataSource;
public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
this.id = id;
this.transactionFactory = transactionFactory;
this.dataSource = dataSource;
}
public static class Builder {
private String id;
private TransactionFactory transactionFactory;
private DataSource dataSource;
public Builder(String id) {
this.id = id;
}
public Builder transactionFactory(TransactionFactory transactionFactory) {
this.transactionFactory = transactionFactory;
return this;
}
public Builder dataSource(DataSource dataSource) {
this.dataSource = dataSource;
return this;
}
public String id() {
return this.id;
}
public Environment build() {
return new Environment(this.id, this.transactionFactory, this.dataSource);
}
}
public String getId() {
return id;
}
public TransactionFactory getTransactionFactory() {
return transactionFactory;
}
public DataSource getDataSource() {
return dataSource;
}
}
MappedStatement.java
package com.lino.mybatis.mapping;
import com.lino.mybatis.session.Configuration;
import java.util.Map;
/**
* @description: 映射器语句类
*/
public class MappedStatement {
private Configuration configuration;
private String id;
private SqlCommandType sqlCommandType;
private BoundSql boundSql;
public MappedStatement() {
}
public static class Builder {
private MappedStatement mappedStatement = new MappedStatement();
public Builder(Configuration configuration, String id, SqlCommandType sqlCommandType, BoundSql boundSql) {
mappedStatement.configuration = configuration;
mappedStatement.id = id;
mappedStatement.sqlCommandType = sqlCommandType;
mappedStatement.boundSql = boundSql;
}
public MappedStatement build() {
assert mappedStatement.configuration != null;
assert mappedStatement.id != null;
return mappedStatement;
}
}
public Configuration getConfiguration() {
return configuration;
}
public String getId() {
return id;
}
public SqlCommandType getSqlCommandType() {
return sqlCommandType;
}
public BoundSql getBoundSql() {
return boundSql;
}
}
Mybatis 框架中我们所需要的基本类型、数组类型以及自定定义的事务实现和事务工厂都需要注册到类型别名注册器中进行管理。
在我们需要使用的时候可以从注册器中获取到具体的对象类型,之后再进行实例化的方式进行使用。
JdbcType.java
package com.lino.mybatis.type;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
/**
* @description: JDBC枚举类型
*/
public enum JdbcType {
// JDBC枚举类型
INTEGER(Types.INTEGER),
FLOAT(Types.FLOAT),
DOUBLE(Types.DOUBLE),
DECIMAL(Types.DECIMAL),
VARCHAR(Types.VARCHAR),
TIMESTAMP(Types.TIMESTAMP);
public final int TYPE_CODE;
private static Map<Integer, JdbcType> codeLookup = new HashMap<>();
static {
for (JdbcType type : JdbcType.values()) {
codeLookup.put(type.TYPE_CODE, type);
}
}
JdbcType(int code) {
this.TYPE_CODE = code;
}
public static JdbcType forCode(int code) {
return codeLookup.get(code);
}
}
TypeAliasRegistry.java
package com.lino.mybatis.type;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* @description: 类型别名注册机
*/
public class TypeAliasRegistry {
private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<>();
public TypeAliasRegistry() {
// 构造函数里注册系统内置的类型别名
registerAlias("string", String.class);
// 基本包装类型
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
}
public void registerAlias(String alias, Class<?> value) {
String key = alias.toLowerCase(Locale.ENGLISH);
TYPE_ALIASES.put(key, value);
}
public <T> Class<T> resolveAlias(String string) {
String key = string.toLowerCase(Locale.ENGLISH);
return (Class<T>) TYPE_ALIASES.get(key);
}
}
TypeAliasRegistry
类型别名注册器中先做一些基本的类型注册,以及提供 registerAlias
注册方法和 resolveAlias
获取方法。Configuration.java
package com.lino.mybatis.session;
import com.lino.mybatis.binding.MapperRegistry;
import com.lino.mybatis.datasource.druid.DruidDataSourceFactory;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.transaction.jdbc.JdbcTransaction;
import com.lino.mybatis.transaction.jdbc.JdbcTransactionFactory;
import com.lino.mybatis.type.TypeAliasRegistry;
import java.util.HashMap;
import java.util.Map;
/**
* @description: 配置项
* @author: lingjian
* @createDate: 2022/11/5 16:27
*/
public class Configuration {
/**
* 环境
*/
protected Environment environment;
/**
* 映射注册机
*/
protected MapperRegistry mapperRegistry = new MapperRegistry(this);
/**
* 映射的语句,存在Map里
*/
protected final Map<String, MappedStatement> mappedStatements = new HashMap<>(16);
/**
* 类型别名注册机
*/
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("DRUID", DruidDataSourceFactory.class);
}
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
public boolean hasMapper(Class<?> type) {
return mapperRegistry.hasMapper(type);
}
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);
}
public MappedStatement getMappedStatement(String id) {
return mappedStatements.get(id);
}
public TypeAliasRegistry getTypeAliasRegistry() {
return typeAliasRegistry;
}
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
Configuration
配置选项中,添加类型别名注册机,通过构造函数添加 JDBC、DRUID 注册操作。通过在 XML 解析器
XMLConfigBuilder
中,扩展对环境信息的解析。这里把数据源、事务类内容成为操作 SQL 环境。
解析后把配置信息写入到 Configuration 配置项中,便于后续使用。
BaseBuilder.java
package com.lino.mybatis.builder;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.type.TypeAliasRegistry;
/**
* @description: 构建器的基类,建造者模式
*/
public class BaseBuilder {
protected final Configuration configuration;
protected final TypeAliasRegistry typeAliasRegistry;
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
}
public Configuration getConfiguration() {
return configuration;
}
}
XMLConfigBuilder.java
package com.lino.mybatis.builder.xml;
import com.lino.mybatis.builder.BaseBuilder;
import com.lino.mybatis.datasource.DataSourceFactory;
import com.lino.mybatis.io.Resources;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.mapping.SqlCommandType;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.transaction.TransactionFactory;
import com.lino.mybatis.type.TypeAliasRegistry;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;
import javax.sql.DataSource;
import java.io.Reader;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @description: XML配置构建器,建造者模式,集成BaseBuilder
*/
public class XMLConfigBuilder extends BaseBuilder {
private Element root;
private static final Pattern pattern = Pattern.compile("(#\\{(.*?)})");
public XMLConfigBuilder(Reader reader) {
// 1.调用父类初始化Configuration
super(new Configuration());
// 2.dom4j 处理xml
SAXReader saxReader = new SAXReader();
try {
Document document = saxReader.read(new InputSource(reader));
root = document.getRootElement();
} catch (DocumentException e) {
e.printStackTrace();
}
}
/**
* 解析配置:类型别名、插件、对象工厂、对象包装工厂、设置、环境、类型转换、映射器
*
* @return Configuration
*/
public Configuration parse() {
try {
// 环境
environmentsElement(root.element("environments"));
// 解析映射器
mapperElement(root.element("mappers"));
} catch (Exception e) {
throw new RuntimeException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
return configuration;
}
private void environmentsElement(Element context) throws Exception {
String environment = context.attributeValue("default");
List<Element> environmentList = context.elements("environment");
for (Element e : environmentList) {
String id = e.attributeValue("id");
if (environment.equals(id)) {
// 事务管理器
TransactionFactory txFactory = (TransactionFactory) typeAliasRegistry.resolveAlias(e.element("transactionManager").attributeValue("type")).newInstance();
// 数据源
Element dataSourceElement = e.element("dataSource");
DataSourceFactory dataSourceFactory = (DataSourceFactory) typeAliasRegistry.resolveAlias(dataSourceElement.attributeValue("type")).newInstance();
List<Element> propertyList = dataSourceElement.elements("property");
Properties props = new Properties();
for (Element property : propertyList) {
props.setProperty(property.attributeValue("name"), property.attributeValue("value"));
}
dataSourceFactory.setProperties(props);
DataSource dataSource = dataSourceFactory.getDataSource();
// 构建环境
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
private void mapperElement(Element mappers) throws Exception {
List<Element> mapperList = mappers.elements("mapper");
for (Element e : mapperList) {
String resource = e.attributeValue("resource");
Reader reader = Resources.getResourceAsReader(resource);
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new InputSource(reader));
Element root = document.getRootElement();
// 命名空间
String namespace = root.attributeValue("namespace");
// SELECT
List<Element> selectNodes = root.elements("select");
for (Element node : selectNodes) {
String id = node.attributeValue("id");
String parameterType = node.attributeValue("parameterType");
String resultType = node.attributeValue("resultType");
String sql = node.getText();
// ? 匹配
Map<Integer, String> parameter = new HashMap<>(16);
Matcher matcher = pattern.matcher(sql);
for (int i = 1; matcher.find(); i++) {
String g1 = matcher.group(1);
String g2 = matcher.group(2);
parameter.put(i, g2);
sql = sql.replace(g1, "?");
}
String msId = namespace + "." + id;
String nodeName = node.getName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
// SQL语句初识化
BoundSql boundSql = new BoundSql(sql, parameter, parameterType, resultType);
MappedStatement mappedStatement = new MappedStatement.Builder(configuration, msId, sqlCommandType, boundSql).build();
// 添加解析SQL
configuration.addMappedStatement(mappedStatement);
}
// 注册Mapper映射器
configuration.addMapper(Resources.classForName(namespace));
}
}
}
XMLConfigBuilder#parse
解析扩展对数据源解析操作, 在 environmentsElement
方法中包括事务管理器解析和从注册器中读取到事务工程的实现类,同理数据源也是从类型注册器中获取。Environment.Builder
存放到 Configuration
配置项中,也就可以通过 Configuration
存在的地方都可以获取到数据源了。DefaultSqlSession.java
package com.lino.mybatis.session.defaults;
import com.lino.mybatis.mapping.BoundSql;
import com.lino.mybatis.mapping.Environment;
import com.lino.mybatis.mapping.MappedStatement;
import com.lino.mybatis.session.Configuration;
import com.lino.mybatis.session.SqlSession;
import java.lang.reflect.Method;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 默认sqlSession实现类
*/
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
public DefaultSqlSession(Configuration configuration) {
this.configuration = configuration;
}
@Override
public <T> T selectOne(String statement) {
return (T) ("你被代理了!" + statement);
}
@Override
public <T> T selectOne(String statement, Object parameter) {
try {
MappedStatement mappedStatement = configuration.getMappedStatement(statement);
Environment environment = configuration.getEnvironment();
Connection connection = environment.getDataSource().getConnection();
BoundSql boundSql = mappedStatement.getBoundSql();
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());
preparedStatement.setLong(1, Long.parseLong(((Object[]) parameter)[0].toString()));
ResultSet resultSet = preparedStatement.executeQuery();
List<T> objList = resultSet2Obj(resultSet, Class.forName(boundSql.getResultType()));
return objList.get(0);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private <T> List<T> resultSet2Obj(ResultSet resultSet, Class<?> clazz) {
List<T> list = new ArrayList<>();
try {
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
// 每次遍历值
while (resultSet.next()) {
T obj = (T) clazz.newInstance();
for (int i = 1; i <= columnCount; i++) {
Object value = resultSet.getObject(i);
String columnName = metaData.getColumnName(i);
String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
Method method;
if (value instanceof Timestamp) {
method = clazz.getMethod(setMethod, LocalDateTime.class);
} else {
method = clazz.getMethod(setMethod, value.getClass());
}
method.invoke(obj, value);
}
list.add(obj);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
@Override
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
@Override
public Configuration getConfiguration() {
return configuration;
}
}
selectOne
方法中获取 Connection
数据源连接,并简单的执行 SQL 语句,并对执行的结果进行封装处理。CREATE TABLE
USER
(
id bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID',
userId VARCHAR(9) COMMENT '用户ID',
userHead VARCHAR(16) COMMENT '用户头像',
createTime TIMESTAMP NULL COMMENT '创建时间',
updateTime TIMESTAMP NULL COMMENT '更新时间',
userName VARCHAR(64),
PRIMARY KEY (id)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into user (id, userId, userHead, createTime, updateTime, userName) values (1, '10001', '1_04', '2022-11-07 00:00:00', '2022-11-07 00:00:00', '小零');
mybatis
的数据库IUserDao.java
package com.lino.mybatis.test.dao;
import com.lino.mybatis.test.po.User;
/**
* @Description: 用户持久层
*/
public interface IUserDao {
/**
* 根据ID查询用户信息
*
* @param uId ID
* @return String 名称
*/
User queryUserInfoById(Long uId);
}
User.java
package com.lino.mybatis.test.po;
import cn.hutool.core.date.DateTime;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @description: 用户实例类
*/
public class User {
private Long id;
/**
* 用户ID
*/
private String userId;
/**
* 头像
*/
private String userHead;
/**
* 用户名称
*/
private String userName;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserHead() {
return userHead;
}
public void setUserHead(String userHead) {
this.userHead = userHead;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
mybatis-config-datasource.xml
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="DRUID">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="mapper/User_Mapper.xml"/>
mappers>
configuration>
mybatis-config-datasource.xml
配置数据源信息,包括:driver、url、username、passwordUser_Mapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lino.mybatis.test.dao.IUserDao">
<select id="queryUserInfoById" parameterType="java.lang.Long" resultType="com.lino.mybatis.test.po.User">
SELECT id, userId, userHead, userName
FROM user
WHERE id = #{id}
select>
mapper>
ApiTest
/**
* 测试映射器注册机
*/
@Test
public void test_SqlSessionFactory() throws IOException {
// 1.从SqlSessionFactory中获取SqlSession
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config-datasource.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2.获取映射器对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 3.测试验证
User user = userDao.queryUserInfoById(1L);
logger.info("测试结果:{}", JSON.toJSONString(user));
}
测试结果
08:32:18.875 [main] INFO c.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
08:32:19.623 [main] INFO com.lino.mybatis.test.ApiTest - 测试结果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小零哥"}
ApiTest
@Test
public void test_selectOne() throws IOException {
// 解析XML
Reader reader = Resources.getResourceAsReader("mybatis-config-datasource.xml");
XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(reader);
Configuration configuration = xmlConfigBuilder.parse();
// 获取 DefaultSqlSession
SqlSession sqlSession = new DefaultSqlSession(configuration);
// 执行查询:默认是一个集合参数
Object[] req = {1L};
Object result = sqlSession.selectOne("com.lino.mybatis.test.dao.IUserDao.queryUserInfoById", req);
logger.info("测试结果:{}", JSON.toJSONString(result));
}
测试结果
10:19:43.519 [main] INFO c.alibaba.druid.pool.DruidDataSource - {dataSource-1} inited
10:19:44.306 [main] INFO com.lino.mybatis.test.ApiTest - 测试结果:{"id":1,"userHead":"1_04","userId":"10001","userName":"小灵哥"}