源码分析-Mybatis源码阅读-Statement语句处理器

源码解析-Mybatis
01 源码分析-Mybatis源码阅读准备
02 源码分析-Mybatis源码阅读-会话层
03 源码分析-Mybatis源码阅读-执行器
04 源码分析-Mybatis源码阅读-Statement语句处理器
05 源码分析-Mybatis源码阅读-参数处理器
06 源码分析-Mybatis源码阅读-结果集处理器
07 源码分析-Mybatis源码阅读-主键生成器
08 源码分析-Mybatis源码阅读-懒加载机制
09 源码分析-Mybatis源码阅读-游标
10 源码分析-Mybatis源码阅读-类型处理器
11 源码分析-Mybatis源码阅读-缓存
12 源码分析-Mybatis源码阅读-Mapper代理

一 语句处理器说明

语句处理器的代码在org.apache.ibatis.executor.statement包下,在03 源码分析-Mybatis源码阅读-执行器 文章中已经有介绍该包下所有类的相关说明。

二 语句处理器相关源码解读

首先,先看一下语句处理器的UML图,如下图:

image-20210514202657121

和执行器类似,在语句处理器中BaseStatementHandler使用了模板方法模式,RoutingStatementHandler使用了装饰模式,了解这两个模式有助于我们更容易阅读源码。

先来看语句处理器接口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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* 语句处理器接口
* @author Clinton Begin
*/
public interface StatementHandler {

/**
* 获取Statement
* @param connection 数据库连接
* @param transactionTimeout 事务超时时间
* @return
* @throws SQLException
*/
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;

/**
* 为语句设置参数
* @param statement 语句
* @throws SQLException
*/
void parameterize(Statement statement)
throws SQLException;

/**
* 批处理操作追加参数集合
* @param statement
* @throws SQLException
*/
void batch(Statement statement)
throws SQLException;

/**
* 执行更新(含插入、修改、删除)
* @param statement
* @return 返回更新的数量
* @throws SQLException
*/
int update(Statement statement)
throws SQLException;

/**
* 执行查询
* @param statement 语句
* @param resultHandler 结果处理器
* @param <E> 泛型结果
* @return 返回查询结果
* @throws SQLException
*/
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;

/**
* 查询游标
* @param statement 语句
* @param <E>
* @return
* @throws SQLException
*/
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;

/**
* 获取绑定SQL
* @return
*/
BoundSql getBoundSql();

/**
* 获取参数处理器
* @return
*/
ParameterHandler getParameterHandler();

}

BaseStatementHandler主要定义了获取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
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* 抽象的语句处理器
* @author Clinton Begin
*/
public abstract class BaseStatementHandler implements StatementHandler {

protected final Configuration configuration;
/** 对象工厂,创建对象时使用 */
protected final ObjectFactory objectFactory;
/** 类型处理器注册表 */
protected final TypeHandlerRegistry typeHandlerRegistry;
protected final ResultSetHandler resultSetHandler;
protected final ParameterHandler parameterHandler;

protected final Executor executor;
protected final MappedStatement mappedStatement;
/** 行边界 */
protected final RowBounds rowBounds;

protected BoundSql boundSql;

protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;

this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();

if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}

this.boundSql = boundSql;

this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}

@Override
public BoundSql getBoundSql() {
return boundSql;
}

@Override
public ParameterHandler getParameterHandler() {
return parameterHandler;
}

@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// 实例化Statement
statement = instantiateStatement(connection);
// 设置Statement超时时间
setStatementTimeout(statement, transactionTimeout);
// 设置查询的条数
setFetchSize(statement);
return statement;
} catch (SQLException e) {
// SQL异常关闭Statement
closeStatement(statement);
throw e;
} catch (Exception e) {
// 关闭Statement
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}

protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

/**
* 设置Statement超时时间
* @param stmt 语句
* @param transactionTimeout 超时时间
* @throws SQLException
*/
protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
Integer queryTimeout = null;
// 映射语句有超时时间则使用映射语句的超时时间 否则使用全局配置的超时时间
if (mappedStatement.getTimeout() != null) {
queryTimeout = mappedStatement.getTimeout();
} else if (configuration.getDefaultStatementTimeout() != null) {
queryTimeout = configuration.getDefaultStatementTimeout();
}
if (queryTimeout != null) {
stmt.setQueryTimeout(queryTimeout);
}
StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
}

/**
* 设置查询条数
* @param stmt 语句
* @throws SQLException
*/
protected void setFetchSize(Statement stmt) throws SQLException {
// 如果映射语句有条数则使用映射语句中的条数设置 否则使用全局默认配置
Integer fetchSize = mappedStatement.getFetchSize();
if (fetchSize != null) {
stmt.setFetchSize(fetchSize);
return;
}
Integer defaultFetchSize = configuration.getDefaultFetchSize();
if (defaultFetchSize != null) {
stmt.setFetchSize(defaultFetchSize);
}
}

protected void closeStatement(Statement statement) {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException e) {
//ignore
}
}

protected void generateKeys(Object parameter) {
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
ErrorContext.instance().store();
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
ErrorContext.instance().recall();
}

}

SimpleStatementHandler简单语句处理器,主要是处理了update过程中,不同的主键生成策略时,创建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
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
/**
* 简单语句处理器
* @author Clinton Begin
*/
public class SimpleStatementHandler extends BaseStatementHandler {

public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}

/**
* 执行更新(含插入、修改、删除)
* @param statement
* @return 返回更新的数量
* @throws SQLException
*/
@Override
public int update(Statement statement) throws SQLException {
String sql = boundSql.getSql();
// 获取参数对象
Object parameterObject = boundSql.getParameterObject();
// 获取主键生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
// 如果是数据库自增的主键生成器
if (keyGenerator instanceof Jdbc3KeyGenerator) {
// 执行SQL 并且返回数据库生成的主键
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
// 获取更新的数量
rows = statement.getUpdateCount();
// 把自增的主键设置到参数对象中
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) { // 如果是通过selectKey方式获取的主键
// 执行SQL
statement.execute(sql);
// 获取更新的数量
rows = statement.getUpdateCount();
// 把selectKey方式获取的主键设置到参数对象中
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
// 执行sql
statement.execute(sql);
rows = statement.getUpdateCount();
}
return rows;
}

@Override
public void batch(Statement statement) throws SQLException {
String sql = boundSql.getSql();
statement.addBatch(sql);
}

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.handleResultSets(statement);
}

@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
String sql = boundSql.getSql();
statement.execute(sql);
return resultSetHandler.handleCursorResultSets(statement);
}

/**
* 实例化语句
* @param connection 数据库连接
* @return
* @throws SQLException
*/
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
// 如果结果集类型是默认类型直接创建Statement
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.createStatement();
} else {
// 否则创建支持并发读的Statement 该Statement不支持update操作
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}

@Override
public void parameterize(Statement statement) {
// N/A
}

}

PrepareStatementHandler预处理语句处理器其实与SimpleStatementHandler差不多,只不过过程中创建的是预处理的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
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
/**
* 预处理的语句处理器
* @author Clinton Begin
*/
public class PreparedStatementHandler extends BaseStatementHandler {

public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}

@Override
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行已预处理的语句
ps.execute();
// 获取更新数量
int rows = ps.getUpdateCount();
// 获取参数对象
Object parameterObject = boundSql.getParameterObject();
// 获取主键生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
// 把返回的主键设置到参数对象中
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}

@Override
public void batch(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.addBatch();
}

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleResultSets(ps);
}

@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleCursorResultSets(ps);
}

/**
* 实例化语句
* @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) {
// 预处理Statement支持返回生成的主键
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
// 主键字段不为空 则指定主键字段返回
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) { // 如果结果集类型是默认类型直接创建预处理Statement
return connection.prepareStatement(sql);
} else { // 否则创建支持并发读的预处理Statement 该预处理Statement不支持update操作
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}

@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}

}

CallableStatementHandler其实与PrepareStatementHandler差不多,只不过多了对输出结果的回调处理,具体源码如下:

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
106
107
108
109
/**
* 支持回调的语句处理器
* @author Clinton Begin
*/
public class CallableStatementHandler extends BaseStatementHandler {

public CallableStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}

@Override
public int update(Statement statement) throws SQLException {
CallableStatement cs = (CallableStatement) statement;
// 执行
cs.execute();
// 获取更新数量
int rows = cs.getUpdateCount();
// 获取参数对象
Object parameterObject = boundSql.getParameterObject();
// 获取主键生成器
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
// 把返回的主键设置到参数对象中
keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);
// 处理输出参数 -- 回调
resultSetHandler.handleOutputParameters(cs);
return rows;
}

@Override
public void batch(Statement statement) throws SQLException {
CallableStatement cs = (CallableStatement) statement;
cs.addBatch();
}

@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
CallableStatement cs = (CallableStatement) statement;
cs.execute();
List<E> resultList = resultSetHandler.handleResultSets(cs);
// 处理输出参数
resultSetHandler.handleOutputParameters(cs);
return resultList;
}

@Override
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
CallableStatement cs = (CallableStatement) statement;
cs.execute();
Cursor<E> resultList = resultSetHandler.handleCursorResultSets(cs);
// 处理输出参数
resultSetHandler.handleOutputParameters(cs);
return resultList;
}

@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
// 默认结果集类型
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareCall(sql);
} else { // 否则创建支持并发读的可回调Statement 该可回调Statement不支持update操作
return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}

/**
* 为语句设置参数
* @param statement 语句
* @throws SQLException
*/
@Override
public void parameterize(Statement statement) throws SQLException {
registerOutputParameters((CallableStatement) statement);
parameterHandler.setParameters((CallableStatement) statement);
}

/**
* 注册输出参数
* @param cs
* @throws SQLException
*/
private void registerOutputParameters(CallableStatement cs) throws SQLException {
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// 遍历参数映射
for (int i = 0, n = parameterMappings.size(); i < n; i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
// 如果是输出参数
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
// 参数不含jdbcType则抛出执行异常
if (null == parameterMapping.getJdbcType()) {
throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty());
} else {
// 如果数值的范围不为空并且jdbc类型数字类型
if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
} else {
// 如果jdbc类型名称为空
if (parameterMapping.getJdbcTypeName() == null) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
} else { // 如果jdbc类型名称不为空空
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
}
}
}
}
}
}

}

RoutingStatementHandler路由语句处理器,会根据映射语句MappedStatement中的StatementType的类型,来创建不同的语句处理器,然后并未对具体的执行器做进一步的包装,源码如下:

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
/**
* 路由语句处理程序
* @author Clinton Begin
*/
public class RoutingStatementHandler implements StatementHandler {

private final StatementHandler delegate;

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());
}

}

@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
return delegate.prepare(connection, transactionTimeout);
}

@Override
public void parameterize(Statement statement) throws SQLException {
delegate.parameterize(statement);
}

@Override
public void batch(Statement statement) throws SQLException {
delegate.batch(statement);
}

@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 <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
return delegate.queryCursor(statement);
}

@Override
public BoundSql getBoundSql() {
return delegate.getBoundSql();
}

@Override
public ParameterHandler getParameterHandler() {
return delegate.getParameterHandler();
}
}