StatementHandler
大约 12 分钟
StatementHandler
JDBC处理器,基于JDBC构建JDBC Statement,并设置参数,然后执行Sql。每调用会话当中一次SQl,都会有与之相对应的且唯一的Statement实例。使用 ParameterHandler 进行参数配置,使用 ResultSetHandler 把查询结果与实体类进行绑定
总共执行过程分为三个阶段:
- 预处理:这里预处理不仅仅是通过Connection创建Statement,还包括设置参数。
- 执行:包含执行SQL和处理结果映射两部分。
- 关闭:直接关闭Statement。
/**
* Statement 处理器,其中 Statement 包含 java.sql.Statement、java.sql.PreparedStatement、java.sql.CallableStatement 三种。
*
* @author Clinton Begin
*/
public interface StatementHandler {
/**
* 准备操作,可以理解成创建 Statement 对象
*
* @param connection Connection 对象
* @param transactionTimeout 事务超时时间
* @return Statement 对象
*/
Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
/**
* 设置 Statement 对象的参数
*
* @param statement Statement 对象
*/
void parameterize(Statement statement) throws SQLException;
/**
* 添加 Statement 对象的批量操作
*
* @param statement Statement 对象
*/
void batch(Statement statement) throws SQLException;
/**
* 执行写操作
*
* @param statement Statement 对象
* @return 影响的条数
*/
int update(Statement statement) throws SQLException;
/**
* 执行读操作
*
* @param statement Statement 对象
* @param resultHandler ResultHandler 对象,处理结果
* @param <E> 泛型
* @return 读取的结果
*/
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
/**
* 执行读操作,返回 Cursor 对象
*
* @param statement Statement 对象
* @param <E> 泛型
* @return Cursor 对象
*/
<E> Cursor<E> queryCursor(Statement statement) throws SQLException;
/**
* @return BoundSql 对象
*/
BoundSql getBoundSql();
/**
* @return ParameterHandler 对象
*/
ParameterHandler getParameterHandler();
}
RoutingStatementHandler 实现类,负责将不同的 Statement 类型,路由到上述三个实现类上
RoutingStatementHandler
实现 StatementHandler 接口,路由的 StatementHandler 对象,根据 Statement 类型,转发到对应的 StatementHandler 实现类中。
/**
* 路由的 StatementHandler 对象,根据 Statement 类型,转发到对应的 StatementHandler 实现类中。
*
* @author Clinton Begin
*/
public class RoutingStatementHandler implements StatementHandler {
/**
* 被委托的 StatementHandler 对象
*/
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 根据不同的类型,创建对应的 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 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();
}
}
BaseStatementHandler
/**
* StatementHandler 基类,提供骨架方法,从而使子类只要实现指定的几个抽象方法即可
*
* @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;
/**
* 一次可执行的 SQL 封装
*/
protected BoundSql boundSql;
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 获得 Configuration 对象
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
// 获得 TypeHandlerRegistry 和 ObjectFactory 对象
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
// 如果 boundSql 非空,一般是写类操作,例如:insert、update、delete ,则先获得自增主键,然后再创建 BoundSql 对象
if (boundSql == null) { // issue #435, get the key before calculating the statement
// 获得自增主键
generateKeys(parameterObject);
// 创建 BoundSql 对象
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
// 创建 ParameterHandler 对象
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 创建 ResultSetHandler 对象
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);
// 设置超时时间
setStatementTimeout(statement, transactionTimeout);
// 设置 fetchSize
setFetchSize(statement);
return statement;
} catch (SQLException e) {
// 发生异常,进行关闭
closeStatement(statement);
throw e;
} catch (Exception e) {
// 发生异常,进行关闭
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
// 设置超时时间
protected void setStatementTimeout(Statement stmt, Integer transactionTimeout) throws SQLException {
// 获得 queryTimeout
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);
}
// 设置 fetchSize
protected void setFetchSize(Statement stmt) throws SQLException {
// 获得 fetchSize 。非空,则进行设置
Integer fetchSize = mappedStatement.getFetchSize();
if (fetchSize != null) {
stmt.setFetchSize(fetchSize);
return;
}
// 获得 defaultFetchSize 。非空,则进行设置
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
}
}
/**
* 获得自增主键
*
* @param parameter 参数对象
*/
protected void generateKeys(Object parameter) {
// 获得 KeyGenerator 对象
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
ErrorContext.instance().store();
// 前置处理,创建自增编号到 parameter 中
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
ErrorContext.instance().recall();
}
}
SimpleStatementHandler
/**
* {@link java.sql.Statement} 的 StatementHandler 实现类
*
* @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);
}
@Override
public int update(Statement statement) throws SQLException {
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
int rows;
// 如果是 Jdbc3KeyGenerator 类型
if (keyGenerator instanceof Jdbc3KeyGenerator) {
// 执行写操作
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
// 获得更新数量
rows = statement.getUpdateCount();
// 执行 keyGenerator 的后置处理逻辑
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
// 如果是 SelectKeyGenerator 类型
} else if (keyGenerator instanceof SelectKeyGenerator) {
// 执行写操作
statement.execute(sql);
// 获得更新数量
rows = statement.getUpdateCount();
// 执行 keyGenerator 的后置处理逻辑
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
// 执行写操作
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);
// 处理返回的 Cursor 结果
return resultSetHandler.handleCursorResultSets(statement);
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.createStatement();
} else {
return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
@Override
public void parameterize(Statement statement) throws SQLException {
// N/A 因为无需做占位符参数的处理。
}
}
PreparedStatementHandler
/**
* {@link java.sql.PreparedStatement} 的 StatementHandler 实现类
*
* @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 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();
// 处理返回的 Cursor 结果
return resultSetHandler.handleCursorResultSets(ps);
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
// 处理 Jdbc3KeyGenerator 的情况
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
// Executor会调用StatementHandler的parameterize方法设置参数。
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
我们已经看了各种 StatementHandler 的实现代码。那么,StatementHandler 对象究竟在 MyBatis 中,是如何被创建的呢?Configuration 类中,提供 #newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
方法,代码如下:
// Configuration.java
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// <1> 创建 RoutingStatementHandler 对象
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 应用插件
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
<1>
处,创建 RoutingStatementHandler 对象。通过它,自动路由到适合的 StatementHandler 实现类。<2>
处,应用插件。
StatementHandler 创建策略有三种。(默认为 PREPARED)
public enum StatementType {
STATEMENT, PREPARED, CALLABLE
}
创建策略到底如何控制?可以在 Mapper.xml 内配置 statementType 属性。
<select id="findAllStudents" resultMap="StudentResult" statementType="STATEMENT">
SELECT * FROM STUDENTS
</select>