【Mybatis】Mybatis执行流程

Mybatis四大组件

Executor:执行器,用来调度StatementHandler、ParameterHandler、ResultHandler等来执行对应的SQL。

StatementHandler:回顾一下JDBC操作数据库的过程,首先加载驱动创建连接,通过连接创建Statement,之后就可以使用Statement进行增删改查操作,在Mybatis中StatementHandler可以看作是对Statement的封装,用于执行数据库操作,它是四大组件的核心。

1
2
3
4
5
6
7
8
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 创建连接
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db_test", "username", "password");
// 通过连接创建Statement
Statement statement = connection.createStatement();
// 通过Statement进行数据库的增删改查操作
ResultSet resultSet = statement.executeQuery("select * from test");

ParameterHandler:用于对查询参数进行处理。

ResultSetHandler:用于执行SQL后对返回的数据集ResultSet的封装处理。

首先,看一下手动加载mybatis配置文件,获取SqlSession的过程:

  1. 加载xml配置文件
  2. 通过SqlSessionFactoryBuilder构建SqlSessionFactory
  3. 通过SqlSessionFactory获取SqlSession
1
2
3
4
5
6
7
8
// mybatis的xml配置文件
String resource = "mybatis-config.xml";
// 加载配置文件,获取文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// SqlSessionFactoryBuilder构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 根据SqlSessionFactory创建SqlSession
SqlSession session = sqlSessionFactory.openSession();

可以看到通过SqlSessionFactoryBuilder可以构建SqlSessionFactory,然后通过SqlSessionFactory就可以获取到SqlSession进行数据库的增删改查操作了,那么就从SqlSessionFactoryBuilder入手看一下Mybatis的执行流程。

Configuration加载

我们知道mybatis是有配置文件的,那么使用mybatis的过程中,首先它一定会去加载配置文件解析各种配置。Configuration加载包括两个部分,一个是解析配置文件,另外一个是创建SqlSessionFactory,这些操作是在SqlSessionFactoryBuilder的build方法中完成的。

1
2
3
4
5
6
7
8
9
<!-- mybatis配置文件 -->
<configuration>
<typeAliases>
<package name="com.springboot.entity"/>
</typeAliases>
<mappers>
<mapper resource="com/springboot/mapper/StudentMapper.xml"/>
</mappers>
</configuration>

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder主要干了两件事情:

  1. 通过传入的文件流,创建了XMLConfigBuilder对象,从名字可以看出这是一个处理XML配置文件相关的类,调用了它的parse方法,解析XML配置文件,然后返回一个Configuration对象。
  2. XML解析结果Configuration作为参数,调用build方法创建了DefaultSqlSessionFactory,DefaultSqlSessionFactory实现了SqlSessionFactory接口,可以作为SqlSessionFactory返回,完成SqlSessionFactory的构建。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class SqlSessionFactoryBuilder {

// 构建SqlSessionFactory
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}

// 省略了其他的build的方法

/**
* 其他build方法最终都是调用这个build方法构建的
* @param inputStream 文件流
* @param environment
* @param properties
* @return
*/
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 构建XMLConfigBuilder,用来解析XML配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
// 调用build方法,创建DefaultSqlSessionFactory,parser.parse()方法用来解析XML文件中的各种配置
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}

public SqlSessionFactory build(Configuration config) {
// 创建一个DefaultSqlSessionFactory返回,它实现了SqlSessionFactory接口
return new DefaultSqlSessionFactory(config);
}
}

配置文件解析

XMLConfigBuilder

XMLConfigBuilder主要用来解析XML配置文件,在parseConfiguration方法中可以看到,对XML文件的各个节点进行了一系列的解析,这里我们先了解一下整体流程,具体的细节可以先不管。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class XMLConfigBuilder extends BaseBuilder {
// 构造函数
public XMLConfigBuilder(Reader reader) {
this(reader, null, null);
}

public XMLConfigBuilder(Reader reader, String environment, Properties props) {
// 创建了XPathParser对象
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}

// 构造函数,初始化
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}

/**
* 解析配置
* @return
*/
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 获取configuration节点,进行配置解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}

// 解析配置
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
// 解析settings
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
// 解析别名
typeAliasesElement(root.evalNode("typeAliases"));
// 解析插件
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析mapper
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
}

创建SqlSessionFactory

SqlSessionFactory

SqlSessionFactory是一个接口,从名字上就可以看出它和SqlSession有关,是创建SqlSession的一个工厂,里面主要包含了openSession和getConfiguration获取Configuration对象的方法。

1
2
3
4
5
6
7
8
9
10
11
12
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);

SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
DefaultSqlSessionFactory

在SqlSessionFactoryBuilder的build方法中可以知道它创建了一个DefaultSqlSessionFactory返回,DefaultSqlSessionFactory实现了SqlSessionFactory接口,它提供了两个方法创建SqlSession,分别是openSessionFromDataSource和openSessionFromConnection,它们都创建的是DefaultSqlSession。

创建DefaultSqlSession需要传入Executor作为参数,所以会先调用Configuration的newExecutor方法创建Executor,在newExecutor方法中会根据传入的ExecutorType生成对应的Executor。

所以DefaultSqlSessionFactory也主要干了两件事:

  1. 创建Executor执行器
  2. 创建DefaultSqlSession
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;

public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}

@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}

// 通过DataSource创建SqlSession
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
// 事务相关
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 根据Configuration创建Executor执行器,默认返回的是SimpleExecutor
final Executor executor = configuration.newExecutor(tx, execType);
// 创建了一个DefaultSqlSession返回
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

// 通过Connection创建SqlSession
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
try {
boolean autoCommit;
try {
// 设置自动提交
autoCommit = connection.getAutoCommit();
} catch (SQLException e) {
// Failover to true, as most poor drivers
// or databases won't support transactions
autoCommit = true;
}
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
final Transaction tx = transactionFactory.newTransaction(connection);
final Executor executor = configuration.newExecutor(tx, execType);
// 创建了一个DefaultSqlSession返回
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
创建Executor
  • SimpleExecutor: 简单执行器,默认使用的执行器就是SimpleExecutor。

  • ReuseExecutor: 可重用执行器。

  • BatchExecutor: 批量执行器,用于进行批量处理。

  • CachingExecutor:缓存执行器,如果开启了缓存,会返回CachingExecutor。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Configuration {
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
//根据类型判断创建哪种类型的执行器
if (ExecutorType.BATCH == executorType) {
// 批量Executor
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
// ReuseExecutor
executor = new ReuseExecutor(this, transaction);
} else {
// 默认的执行器
executor = new SimpleExecutor(this, transaction);
}
//如果开启了缓存,创建缓存执行器(装饰者模式)
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
}

查询过程的执行

经过上面的步骤,拿到了一个DefaultSqlSessionFactory,接下来就可以通过DefaultSqlSessionFactory来获取SqlSession对象了,默认返回的是DefaultSqlSession,获取到SqlSession就可以对数据库进行增删改查了。

DefaultSqlSession

DefaultSqlSession中实现了SqlSession接口中的增删改查方法,以selectList查询方法为例,可以看到最终是通过执行器进行查询的,那么接下来就以SimpleExecutor为例,看一下Mybatis的查询过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class DefaultSqlSession implements SqlSession {

private final Configuration configuration;
private final Executor executor;

...

@Override
public <E> List<E> selectList(String statement) {
return this.selectList(statement, null);
}

@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
// 从配置类中获取MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
// 通过执行器Executor进行查询
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

...
}

SimpleExecutor

Mybatis默认使用的执行器是SimpleExecutor,进入SimpleExecutor的query方法查看一下执行过程,query方法实际是在其父类BaseExecutor实现的,所以先进入BaseExecutor的query方法,这里我们只需要关注queryFromDatabase方法即可,和缓存有关的先不管:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public abstract class BaseExecutor implements Executor {

@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
...
try {
queryStack++;
//从缓存中获取数据,key的类型为CacheKey
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//如果获取结果为空,从数据库中查找
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
...
return list;
}

// 从数据库中查询
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
// 放入缓存
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 执行查询,由BaseExecutor子类实现doQuery方法
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
// 放入缓存
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
}

SimpleExecutor的doQuery方法:

  1. 获取Configuration配置类

  2. 生成StatementHandler

  3. 创建Statement
  4. Statement参数处理
  5. 调用StatementHandler的query方法进行查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class SimpleExecutor extends BaseExecutor {
// 查询
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// 获取Configuration
Configuration configuration = ms.getConfiguration();
// 生成StatementHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 创建Statement
stmt = prepareStatement(handler, ms.getStatementLog());
// 通过StatementHandler执行查询
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}

// 生成Statement并处理参数
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
// prepare由StatementHandler由子类实现,用于完成JDBC Statement接口的实例化
stmt = handler.prepare(connection, transaction.getTimeout());
// 处理Statement对应的参数
handler.parameterize(stmt);
return stmt;
}
}

StatementHandler的生成

StatementHandler的生成是在Configuration中的newStatementHandler方法中实现的, 可以看到创建了一个RoutingStatementHandler返回。

1
2
3
4
5
6
7
8
9
public class Configuration {
// 创建StatementHandler
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//创建RoutingStatementHandler
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
}

RoutingStatementHandler的构造函数中,根据StatementType进行判断生成哪种类型的StatementHandler,一共有三种类型:

  • SimpleStatementHandler

  • PreparedStatementHandler

  • CallableStatementHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

public class RoutingStatementHandler implements StatementHandler {

private final StatementHandler delegate;

/**
* 构造函数
* @param executor
* @param ms
* @param parameter
* @param rowBounds
* @param resultHandler
* @param boundSql
*/
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//根据类型判断创建哪种处理器
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}

}
}

Statement的生成

StatementHandler的prepare方法负责生成Statement,以PreparedStatementHandler为例,看一下Statement的生成过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public abstract class BaseStatementHandler implements StatementHandler {

// 生成Statement
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// 这里初始化JDBC的Statement对象,instantiateStatement方法由子类实现
statement = instantiateStatement(connection);
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
// 返回statement
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
}

public class PreparedStatementHandler extends BaseStatementHandler {
/**
* 初始化JDBC statement
* @param connection
* @return
* @throws SQLException
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
// 通过Connection创建prepareStatement对象
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() != null) {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.prepareStatement(sql);
}
}
}

可以看到,最终通过Connection创建了PrepareStatement。

Statement参数处理

Statement生成之后,调用了parameterize方法进行参数处理,实际上是调用ParameterHandler的setParameters方法对Statement进行参数设置:

1
2
3
4
5
6
7
8
public class PreparedStatementHandler extends BaseStatementHandler {
protected final ParameterHandler parameterHandler;//参数处理器
// 处理参数
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);//设置参数
}
}

ParameterHandler只是一个接口,它有一个子类DefaultParameterHandler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public interface ParameterHandler {
Object getParameterObject();
void setParameters(PreparedStatement ps)
throws SQLException;

}

public class DefaultParameterHandler implements ParameterHandler {

private final TypeHandlerRegistry typeHandlerRegistry;
private final MappedStatement mappedStatement;
private final Object parameterObject;
private final BoundSql boundSql;
private final Configuration configuration;
...

// 设置参数
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 获取类型处理器
TypeHandler typeHandler = parameterMapping.getTypeHandler();
// 获取参数的JDBC类型
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 设置参数,setParameter在BaseTypeHandler实现的
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}

}

其中TypeHandler用于实现JAVA类型和JDBC类型的转换,它会根据参数的JAVA类型和JDBC类型选择合适的TypeHandler,再通过TypeHandler进行参数设置,以此达到JAVA类型到JDBC类型的转换。

1
2
3
4
5
<select id="getStudentById" resultMap="studentMap" parameterType="String">
SELECT *
FROM STUDENT
WHERE ID = #{id,javaType=String,jdbcType=VARCHAR}
</select

通过#{id,javaType=String,jdbcType=VARCHAR}可知JAVA类型是String,JDBC类型是VARCHAR,因此mabatis会使用StringTypeHandler进行参数处理。

BaseTypeHandler

进入BaseTypeHandler的setParameter看下参数的设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {

...

@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
// 类型为空时调用
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
"Cause: " + e, e);
}
} else {
try {
//当类型不为空时调用,由子类实现
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different configuration property. " +
"Cause: " + e, e);
}
}
}

// 以StringTypeHandler为例
public class StringTypeHandler extends BaseTypeHandler<String> {

@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
ps.setString(i, parameter);//通过PreparedStatement的setString方法设置参数
}
...
}

StatementHandler的查询

由SimpleExecutor的doQuery方法可知,生成StatementHandler和Statement之后,调用了StatementHandler的query方法进行最终的查询,那么再次进入到PreparedStatementHandler,看下一下查询过程的执行:

1
2
3
4
5
6
7
8
9
10
11
12
public class PreparedStatementHandler extends BaseStatementHandler {
// 执行查询
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// 转成PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
// 执行查询
ps.execute();
// 通过ResultSetHandler处理查询结果
return resultSetHandler.<E> handleResultSets(ps);
}
}

查询结果的处理

在PreparedStatementHandler的query方法中,最后通过ResultSetHandler的handleResultSets方法对statement的查询结果进行了处理。

ResultSetHandler只是一个接口,handleResultSets()方法在它的子类DefaultResultSetHandler中实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public interface ResultSetHandler {
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
<E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException;
void handleOutputParameters(CallableStatement cs) throws SQLException;

}

public class DefaultResultSetHandler implements ResultSetHandler {
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

final List<Object> multipleResults = new ArrayList<Object>();

int resultSetCount = 0;
// 获取第一个结果
ResultSetWrapper rsw = getFirstResultSet(stmt);
// 从mappedStatement获取ResultMap
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
// 将结果转为ResultMap对象
handleResultSet(rsw, resultMap, multipleResults, null);
// 获取下一个结果集
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}

String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
while (rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
handleResultSet(rsw, resultMap, null, parentMapping);
}
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
}
return collapseSingleResultList(multipleResults);
}
}

参考:

五月的仓颉:MyBatis源码分析

acm_lkl:mybatis TypeHandler详解