0%

mybatis之StatementHandler

StatementHandler数据库交互

StatementHandler接口是mybatis的核心接口之一,StatementHandler接口中功能很多,进行预编译并且调用ParameterHandler的setParameters()方法设置参数,创建Statement对象,通过ParameterHandler为SQL语句绑定实参,执行select、insert、update、delete等多种类型的SQL语句,批量执行SQL语句,通过ResultSetHandler将结果集映射成结果对象。

StatementHandler流程

  • 创建: 由Configuration方法中newStatementHandler()方法生成的,生成的是RoutingStatementHandler
  • 选择: RoutingStatementHandler的通过适配器模式找到对应(根据上下文)的StatementHandler执行的,并且有SimpleStatementHandler、PrepareStatementHandler、CallableStatementHandler
  • Executor会调用StatementHandler的prepare方法创建Statement,调用parameterize方法通过ParameterHandler设置参数,完成预编译(只有Statement为PreparedStatement时才会进行预编译)
  • 最后调用ResultSetHandler封装结果集
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 interface StatementHandler {
// 从连接中获取一个Statement
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
// 绑定statement执行时所需的实参
void parameterize(Statement statement)
throws SQLException;
// 批量执行SQL语句
void batch(Statement statement)
throws SQLException;
// 执行update/insert/delete语句
int update(Statement statement)
throws SQLException;
// 执行select语句
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;

<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;

BoundSql getBoundSql();
// 获取其中封装的ParameterHandler
ParameterHandler getParameterHandler();
}

StatementHandler有两个实现类RoutingStatementHandler和BaseStatementHandler

BaseStatementHandler

BaseStatementHandler是实现了一个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
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
public abstract class BaseStatementHandler implements StatementHandler {
protected final Configuration configuration;
protected final ObjectFactory objectFactory;
protected final TypeHandlerRegistry typeHandlerRegistry;
// 将结果集映射为对象
protected final ResultSetHandler resultSetHandler;
// 主要是为SQL语句绑定实参,使用传入的实参替换SQL语句的中?占位符
protected final ParameterHandler parameterHandler;
// 记录执行SQL语句的Executor对象
protected final Executor executor;
// 记录SQL语句对应的MappedStatement
protected final MappedStatement mappedStatement;
// 记录用户设置的offset和limit,用于用在结果集中定位映射的起始位置和结束位置
protected final RowBounds rowBounds;
// 记录SQK语句对应的BoundSql
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 = this.configuration.getTypeHandlerRegistry();
this.objectFactory = this.configuration.getObjectFactory();
if (boundSql == null) {
// 调用keyGenerator的processBefore方法获取主键
this.generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}

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

public BoundSql getBoundSql() {
return this.boundSql;
}

public ParameterHandler getParameterHandler() {
return this.parameterHandler;
}
// 实现StatementHandler的prepare方法
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(this.boundSql.getSql());
Statement statement = null;

try {
// 初始化Statement对象,由子类实现(模板方法模式)
statement = this.instantiateStatement(connection);
this.setStatementTimeout(statement, transactionTimeout);
this.setFetchSize(statement);
return statement;
} catch (SQLException var5) {
this.closeStatement(statement);
throw var5;
} catch (Exception var6) {
this.closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + var6, var6);
}
}

protected abstract Statement instantiateStatement(Connection var1) throws SQLException;

protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
Integer queryTimeout = null;
if (this.mappedStatement.getTimeout() != null) {
queryTimeout = this.mappedStatement.getTimeout();
} else if (this.configuration.getDefaultStatementTimeout() != null) {
queryTimeout = this.configuration.getDefaultStatementTimeout();
}

if (queryTimeout != null) {
stmt.setQueryTimeout(queryTimeout);
}

StatementUtil.applyTransactionTimeout(stmt, queryTimeout, transactionTimeout);
}

protected void setFetchSize(Statement stmt) throws SQLException {
Integer fetchSize = this.mappedStatement.getFetchSize();
if (fetchSize != null) {
stmt.setFetchSize(fetchSize);
} else {
Integer defaultFetchSize = this.configuration.getDefaultFetchSize();
if (defaultFetchSize != null) {
stmt.setFetchSize(defaultFetchSize);
}

}
}

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

}

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

在BoundSql中记录的SQL语句中可能包含”?”占位符,而每个”?”占位符都对应了BoundSql.parameterMappings集合中的一个元素,ParameterMapping对象中记录了对应参数的名称以及相关属性
在ParameterHandler中的setParameters方法负责为SQL语句绑定实参,该接口只有一个实现类DefaultParameterHandler,遍历BoundSql.parameterMappings集合,根据ParameterMapping对象中记录的参数名称查找相应的实参,通过TypeHandler转换为JdbcType

SimpleStatementHandler

SimpleStatementHandler继承了BaseStatementHandler抽象类,底层直接使用java.sql.Statement对象来操作数据库,SQL中不能存在占位符,parameterize方法为空实现

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

//增删改都会走update方法
public int update(Statement statement) throws SQLException {
String sql = this.boundSql.getSql();
Object parameterObject = this.boundSql.getParameterObject();
KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
int rows;
if (keyGenerator instanceof Jdbc3KeyGenerator) {
statement.execute(sql, 1);
// 受影响的行数
rows = statement.getUpdateCount();
// 数据库生成的主键添加到parameterObject中
keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
statement.execute(sql);
rows = statement.getUpdateCount();
keyGenerator.processAfter(this.executor, this.mappedStatement, statement, parameterObject);
} else {
statement.execute(sql);
rows = statement.getUpdateCount();
}

return rows;
}

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

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

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

// 初始化Statement
protected Statement instantiateStatement(Connection connection) throws SQLException {
// 直接使用Connection对象创建Statement对象
return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.createStatement() : connection.createStatement(this.mappedStatement.getResultSetType().getValue(), 1007);
}

public void parameterize(Statement statement) {
}
}

PreparedStatementHandler

PreparedStatementHandler继承了BaseStatementHandler抽象类,底层使用java.sql.PreparedStatement对象来操作数据库,PreparedStatement是预编译的,可以在sql语句中存在”?”占位符,parameterize方法通过调用ParameterHandler.setParameters()方法完成SQL语句的参数绑定

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

public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
ps.execute();
int rows = ps.getUpdateCount();
Object parameterObject = this.boundSql.getParameterObject();
KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
return rows;
}

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

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

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

//初始化Statement,进行预编译
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = this.boundSql.getSql();
// 根据mappedStatement.getKeyGenerator()字段的值,创建PrepareStatement
if (this.mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = this.mappedStatement.getKeyColumns();
return keyColumnNames == null ? connection.prepareStatement(sql, 1) : connection.prepareStatement(sql, keyColumnNames);
} else {
return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.prepareStatement(sql) : connection.prepareStatement(sql, this.mappedStatement.getResultSetType().getValue(), 1007);
}
}

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

CallableStatementHandler

CallableStatementHandler继承了BaseStatementHandler抽象类,底层使用java.sql.CallableStatement调用指定的存储过程,其parameterize方法通过调用ParameterHandler.setParameters()方法完成SQL语句的参数绑定,并指定输出参数的索引位置和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
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
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);
}

public int update(Statement statement) throws SQLException {
CallableStatement cs = (CallableStatement)statement;
cs.execute();
int rows = cs.getUpdateCount();
Object parameterObject = this.boundSql.getParameterObject();
KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
keyGenerator.processAfter(this.executor, this.mappedStatement, cs, parameterObject);
this.resultSetHandler.handleOutputParameters(cs);
return rows;
}

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

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
CallableStatement cs = (CallableStatement)statement;
cs.execute();
List<E> resultList = this.resultSetHandler.handleResultSets(cs);
this.resultSetHandler.handleOutputParameters(cs);
return resultList;
}

public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
CallableStatement cs = (CallableStatement)statement;
cs.execute();
Cursor<E> resultList = this.resultSetHandler.handleCursorResultSets(cs);
this.resultSetHandler.handleOutputParameters(cs);
return resultList;
}

protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = this.boundSql.getSql();
return this.mappedStatement.getResultSetType() == ResultSetType.DEFAULT ? connection.prepareCall(sql) : connection.prepareCall(sql, this.mappedStatement.getResultSetType().getValue(), 1007);
}

public void parameterize(Statement statement) throws SQLException {
this.registerOutputParameters((CallableStatement)statement);
this.parameterHandler.setParameters((CallableStatement)statement);
}

private void registerOutputParameters(CallableStatement cs) throws SQLException {
List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
int i = 0;

for(int n = parameterMappings.size(); i < n; ++i) {
ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
if (null == parameterMapping.getJdbcType()) {
throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty());
}

if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());
} else if (parameterMapping.getJdbcTypeName() == null) {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);
} else {
cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());
}
}
}

}
}

RoutingStatementHandler

RoutingStatementHandler是StatementHandler接口的另一个实现类,会根据MappedStatement中指定的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
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 RoutingStatementHandler implements StatementHandler {
private final StatementHandler delegate;

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 根据statementType来设置相应的接口实现
switch(ms.getStatementType()) {
case STATEMENT:
this.delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
this.delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
this.delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}

}

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

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

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

public int update(Statement statement) throws SQLException {
return this.delegate.update(statement);
}

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
return this.delegate.query(statement, resultHandler);
}

public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
return this.delegate.queryCursor(statement);
}

public BoundSql getBoundSql() {
return this.delegate.getBoundSql();
}

public ParameterHandler getParameterHandler() {
return this.delegate.getParameterHandler();
}
}

欢迎关注我的其它发布渠道