Mybatis本质上是一个JDBC框架,但是之前分析的内容跟JDBC的关系还不是很明显,实际上JDBC相关的操作全部封装到了StatementHandler
组件中,一个SQL请求经过会话,到达执行器,最终由StatmentHandler执行JDBC来操作数据库。
照例先来回顾一下基本的流程:

关于执行器的相关原理,之前已经做过详细分析,参见以下两篇文章:
何时创建?
StatementHandler
由BaseExecutor
的子类负责创建,以SimpleExecutor
为例,来看一下是如何创建的。
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
|
public class SimpleExecutor extends BaseExecutor {
// 省略其他代码...
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 创建StatementHandler对象
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 构建Statement对象
stmt = prepareStatement(handler, ms.getStatementLog());
// 使用StatementHandler处理Statement,执行SQL
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
// 与doUpdate类似,省略代码..
}
// 省略其他...
}
|
在Executor
的doQuery()
/ doUpdate()
等实现中,每次都通过Configuration
对象构建了一个新的StatementHandler
对象
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
|
public class Configuration {
// 省略其他代码...
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;
}
// 省略其他代码...
}
// 动态装饰器
public class RoutingStatementHandler implements StatementHandler {
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 通过配置的StatementType类型(默认是Prepared),来构建不同的委托实现类(StatementHandler)
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());
}
}
@Override
public int update(Statement statement) throws SQLException {
return delegate.update(statement);
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
return delegate.query(statement, resultHandler);
}
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
return delegate.prepare(connection, transactionTimeout);
}
// 其余实现同上,忽略,都是通过委托对象调用相关的实现方法。
}
|
RoutingStatementHandler
的实现目前看起来有点迷,有点像是无意义的封装,其核心逻辑就是通过配置的StatementType
来构建不同的StatementHandler
,实现动态装饰器,可能是我的道行还比较浅,不太明白这样做的意义是什么,如果换我来实现,可能就是类似这样的:
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
|
public class Configuration {
// 省略其他代码...
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = null; //new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
switch (mappedStatement.getStatementType()) {
case STATEMENT:
statementHandler = new SimpleStatementHandler(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
statementHandler = new PreparedStatementHandler(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
statementHandler = new CallableStatementHandler(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + mappedStatement.getStatementType());
}
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
// 省略其他代码...
}
|
类结构
StatementHandler是一个顶层的接口,定义了JDBC相关的操作方法:
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 interface StatementHandler {
// 声明Statement对象
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
// 为Statement处理参数
void parameterize(Statement statement)
throws SQLException;
// 添加批处理,即:statement.addBatch()
void batch(Statement statement)
throws SQLException;
// 执行update操作
int update(Statement statement)
throws SQLException;
// 执行query操作
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
// 获取动态SQL
BoundSql getBoundSql();
// 获取参数处理器
ParameterHandler getParameterHandler();
}
|

实现类很简单,其中RoutingStatementHandler
咱们刚才已经看过了,其余3个分别对应JDBC中的Statement
,PreparedStatement
,CallableStatement
对象。

大部分情况下,都是使用PreparedStatementHandler
(默认值)如果需要使用其他类型的处理器,通过这样配置即可:
1
2
3
4
5
|
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = ##{id}")
@Options(statementType = StatementType.STATEMENT)
User findById(@Param("id") Integer id);
}
|
执行流程
接下来了解StatementHandler
的完整执行流程(以PreparedStatementHandler
为例)先来看下图

总体来说,执行过程共分为了三个阶段:
- 预处理:这里不仅仅是通过
Connection
创建Statement
对象,同时还包含了参数的处理。
- 执行SQL:包含执行SQL以及对数据库返回结果的映射。
- 关闭:直接关闭
Statement
。

首先是创建StatementHandler
对象(由RoutingStatementHandler
装饰PreparedStatementHandler
对象)

接着使用handler.prepare()
创建PreparedStatement
对象,同时调用handler.parameterize()
进行参数预处理。
需要注意的是,由于配置了输出日志,所以Connection
以及PreparedStatement
都是分别由ConnectionLogger
和PreparedStatementLogger
两个类进行动态代理的,其目的就是为了实现日志输出。
如果将日志输出的配置取消,则上述的两个对象不会经过Mybatis的动态代理包装,而是直接实例化JDBC的原始对象。
1
2
3
4
|
<settings>
<setting name="cacheEnabled" value="true"/>
<!-- <setting name="logImpl" value="STDOUT_LOGGING"/>-->
</settings>
|

关于日志输出的动态代理实现,后续有时间再深入分析,咱们再继续跟进StatementHandler
的执行流程。

继续调用handler.query()
方法,执行JDBC的PreparedStatement.execute()
方法,完成SQL调用,最后由ResultSetHandler
处理执行结果,最终由最外层的finally
代码块执行closeStatement()
方法,则完成了全部的流程。
此外,上图中还有个小细节,在query()
中定义了resultHandler
参数,但是并没有传值和使用,而是直接使用的是BaseStatementHandler
中定义的DefaultResultSetHandler
,这是为什么呢?这个行参目前来看好像是没有作用的,还是比较迷惑的。
参数处理
参数处理以及结果集封装,可能是整个流程中最为复杂和繁琐的部分了,所以分别用了ParameterHandler
以及ResultSetHandler
两个专门的组件来实现这些复杂的逻辑,接下来先来看一下参数处理的详细过程。
何为参数处理?换句话说,如何将Mapper
中定义的参数赋值到SQL语句中?总的来说,要经过3个步骤,参数转换、参数映射、参数赋值。

参数转换
即将Mapper
定义的方法中的普通参数,转换成Map
,以便于Map
中的key
与SQL模板中引用相对应。
1
2
3
4
5
6
7
8
9
10
11
12
|
public interface User2Mapper {
// 未使用@Param注解,则SQL模板中使用变量age0,age1或者param1,param2...
@Select("SELECT * FROM user WHERE name = ##{arg0} AND age = ##{arg1}")
User findByNameAndAge(String name, Integer age);
@Select("SELECT * FROM user WHERE name = ##{name} AND age = ##{id}")
User findByNameAndId(@Param("name") String name, @Param("id") Integer id);
@Select("SELECT * FROM user WHERE id = ##{id}")
User findById(Integer id);
}
|
在调用user2Mapper.findByNameAndAge()
函数后,经过Mapper
动态代理,最终由ParamNameResolver
转换器负责对参数进行转换,关于Mapper
的动态代理,以后我会专门整理一篇文章来说明,这里先看一个简单的动态代理流程图。

参数的转换处理将在MapperMethod.MethodSignature
中触发,来看看关键的源代码
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
// 省略其他...
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
// 对Mapper定义的参数进行转换
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
// 对Mapper定义的参数进行转换
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
// 对Mapper定义的参数进行转换
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
// 对Mapper定义的参数进行转换
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
// 省略其他代码...
}
public static class MethodSignature {
// 省略其他..
private final ParamNameResolver paramNameResolver;
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
// 省略其他..
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
public Object convertArgsToSqlCommandParam(Object[] args) {
// 调用ParamNameResolver.getNamedParams() 完成参数转换
return paramNameResolver.getNamedParams(args);
}
// 省略其他..
}
}
|
其核心逻辑最终在ParamNameResolver.getNamedParams()
中完成,来看关键代码:
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
public class ParamNameResolver {
// 默认的参数名前缀
public static final String GENERIC_NAME_PREFIX = "param";
// 是否使用实际的参数名
private final boolean useActualParamName;
// 有顺序的参数列表
private final SortedMap<Integer, String> names;
// 是否有@Param注解
private boolean hasParamAnnotation;
public ParamNameResolver(Configuration config, Method method) {
this.useActualParamName = config.isUseActualParamName();
// 使用反射获取参数列表、参数定义的注解列表
final Class<?>[] paramTypes = method.getParameterTypes();
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<>();
int paramCount = paramAnnotations.length;
// 根据方法行参数定义的@Param初始化names
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// skip special parameters
continue;
}
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// @Param was not specified.
if (useActualParamName) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// use the parameter index as the name ("0", "1", ...)
// gcode issue ##71
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
// 省略其他
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null; // 无参数,返回null
}
// 没有@Param注解,且只有一个参数,直接取第一个
else if (!hasParamAnnotation && paramCount == 1) {
Object value = args[names.firstKey()];
// 只有一个参数,判断是否为list或者array,如果是,再包装一层
return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null);
} else {
// 多个参数,转换成map
final Map<String, Object> param = new ParamMap<>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
// names有3种情况
// 1. 未定义@Param注解,默认为arg0, age1
// 2. 未定义@Param注解,JDK8以上,且开启了“-parameters”编译参数,则names为实际的参数名
// 3. 定义了@Pram注解,则值为@Param定义的名字
param.put(entry.getValue(), args[entry.getKey()]);
// 除反射获取的名称外,再加入通用参数名(param1, param2...)
final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
public static Object wrapToMapIfCollection(Object object, String actualParamName) {
if (object instanceof Collection) {
ParamMap<Object> map = new ParamMap<>();
map.put("collection", object);
if (object instanceof List) {
map.put("list", object);
}
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
} else if (object != null && object.getClass().isArray()) {
ParamMap<Object> map = new ParamMap<>();
map.put("array", object);
Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
return map;
}
return object;
}
}
|
参数转换的核心逻辑就分析完了,来简单总结一下:
- 单个参数:且没有设置
@Param
注解会直接转换,忽略SQL中的引用名称
- 多个参数:如果有
@Param
注解,则使用注解中定义的名称,反之使用反射获取的参数名(arg0, arg1...
)此外,再加入通用的参数名(param1, param2..
.)
- 可以通过指定JDK8编译参数(“
-parameters
”)来省略@Param
注解,一般不建议使用。
参数映射
那么在参数转换完成之后,将转换后的parameterMap
交由SqlSession
门面传递给Executor
进行执行
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
|
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 = ms.getConfiguration();
// 构建StatementHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// SQL预编译
stmt = prepareStatement(handler, ms.getStatementLog());
// 执行查询
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
// 参数处理
handler.parameterize(stmt);
return stmt;
}
}
|
在StatementHandler.parameterize()
中,又将参数对象交由了ParameterHandler
进行处理
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
63
64
65
66
67
68
69
70
71
|
public class PreparedStatementHandler extends BaseStatementHandler {
protected final ParameterHandler parameterHandler;
protected final ResultSetHandler resultSetHandler;
// 省略其他代码..
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 省略其他代码...
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
@Override
public void parameterize(Statement statement) throws SQLException {
// 交由parameterHandler处理参数
parameterHandler.setParameters((PreparedStatement) statement);
}
}
public class DefaultParameterHandler implements ParameterHandler {
// 省略其他代码...
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 获取boundSql中包装后的参数对象,
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;
}
// 如果有自定义的参数转换器,则无需映射,后面由自定义的TypeHandler进行赋值
else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
// 使用反射工具类进行参数转换,支持格式如:username, user.name等
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 由TypeHandler进行参数赋值
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}
|
由此可见,参数映射的核心关键,就是这个MetaObject
的反射工具类,这也是Mybatis中相当重要的一个组件,这里暂时不去研究底层的实现细节,咱们只需要知道,该工具类提供强大的反射功能,可以根据传入的propertyName
获取对应传入的参数值。
参数映射完成后,拿到了具体参数的值,比如:user.name = "张三"
,接下来就是将其设置到SQL中,这时就轮到TypeHandler
出场了。
参数赋值
1
2
3
4
5
6
7
8
9
10
11
|
public interface TypeHandler<T> {
// 设置参数
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
// 获取结果集
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
|
TypeHandler
定义了两种方法,设置参数以及获取结果集,再来看看具体的实现类都是怎么实现参数设置的。

从图中可以看到,TypeHandler
有很多实现类,针对每种数据类型都会有其自己的实现类,来看最常用的StringTypeHandler
实现,首先会经过所有TypeHandler
的父类BaseTypeHandler
,该类是一个典型的模板设计方法:
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
|
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 {
// 参数不为空时,交由具体的实现类实现,子类只需实现setNonNullParameter即可。
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);
}
}
}
// 省略结果集处理相关
public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
}
public class StringTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType)
throws SQLException {
// 调用jdbc中的PreparedStatement.setString()完成参数赋值
ps.setString(i, parameter);
}
// 省略结果集处理相关..
}
|
参数的处理到这里就完成了,经过一系列的跳转,多个组件的传递后,最终调用了JDBC的底层API,实现了参数赋值。
结果集处理
回顾之前的代码,在StatmentHandler
中调用PreparedStatment.execute()
后,待SQL执行完成,就该处理结果了
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 ps = (PreparedStatement) statement;
ps.execute();
// 使用resultSetHandler处理SQL返回结果
return resultSetHandler.handleResultSets(ps);
}
}
|
resultSetHandler
的实例化在其BaseStatementHandler
父类中完成,关于结果集的转换,99%的逻辑都在唯一的实现类DefaultResultSetHandler
中完成。

简单来说,整理的流程可以大致描述为:
- 读取结果集
- 遍历结果集中的当前行
- 创建对象
- 填充属性
该类的内容比较多,咱们用代码调试的方式,挑重要的部分来看

首先是通过mappedStatment.getResultMaps()
读取结果集,紧接着开始依次遍历,如图中所示,获取到一条数据,返回结果为List<ResultMap>
,针对当前行的数据,再继续调用handleResultSet()
方法。

再接着调用handleRowValues()
返回,处理当前行的ResultMap
对象。

这里又经过了2个分支,其中分别对应的是处理嵌套结果handleRowValuesForNestedResultMap()
以及处理简单结果handleRowValuesForSimpleResultMap()

通过调用getRowValue()
来创建对象,再继续往下看

即先通过createResultObject()
创建一个空对象(即通过无参构造函数),接着使用MetaObject
对象对其进行属性的填充,主要分为两个部分,首先是applyAutomaticMappings()
方法负责自动填充属性,然后再由applyPropertyMappings()
负责填充手动映射的一些属性。此外,这里还涉及到一些懒加载代理相关的逻辑,就暂不研究了。
评论