1.StatementHandler概要
MyBatis一个基于JDBC的Dao框架,会话、执行器半点没有提到jdbc,原因是MyBatis把所有跟JDBC相关的操作全部都放到了StatementHandler中。
一个SQL请求会经过会话,然后是执行器,最由StatementHandler执行jdbc最终到达数据库。其关系如下图:
这里要注意这三者之间比例是1:1:n。也就是说多个SQL操作对应一个会话,和唯一的执行器以及N个StatementHandler。这里的N取决于通过会话调用了多少次Sql(命中缓存除外)。
2.StatementHandler定义
JDBC处理器,基于JDBC构建JDBC Statement,并设置参数,然后执行Sql。每调用会话当中一次SQL,都会有与之相对应的且唯一的Statement实例。
2.1StatementHandler结构
StatementHandler接口定义了JDBC操作的相关方法如下:
/**
* JDBC语句处理器
*/
public interface StatementHandler {
// 准备语句
Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException;
// 参数化
void parameterize(Statement statement)
throws SQLException;
// 添加批处理(并非执行)
// sqlSession直接flushStatements或SqlSession commit
void batch(Statement statement)
throws SQLException;
// 更新
int update(Statement statement)
throws SQLException;
// select-->ResultHandler不为空时结果给ResultHandler
<E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException;
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
// 得到绑定sql
BoundSql getBoundSql();
// 得到参数处理器
ParameterHandler getParameterHandler();
}
StatementHandler 有三个子类SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler,分别对应JDBC中的Statement、PreparedStatement、CallableStatement。
RoutingStatementHandler,采用委派模式,所有的操作都由RoutingStatementHandler执行后到具体的StatementHandler
具体的类结构关系图如下:
2.2StatementHandler初始化
// Executor执行器中查询最终查询数据的代码
@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();
// 构建RoutingStatementHandler,采用委派模式。delegate根据具体的statementType构建相应的StatementHandler
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 构建对应的Statement,并设置参数
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);
// 初始化Statement
stmt = handler.prepare(connection, transaction.getTimeout());
// 设置参数
handler.parameterize(stmt);
return stmt;
}
2.3RoutingStatementHandler
public class RoutingStatementHandler implements StatementHandler {
// 具体委派的对象
private final StatementHandler delegate;
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 根据不同的StatementType,构建不同的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());
}
}
// 以下委派具体的StatementHandler处理
@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();
}
}
2.4BaseStatementHandler
BaseStatementHandler 采用模板方法设计模式,定义了一系列模板方法,具体的不同在其子类中。
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;
}
// 初始化Statement
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// 实例化Statement,具体的在其子类
statement = instantiateStatement(connection);
// 设置超时,其实就是调用Statement.setQueryTimeout。
setStatementTimeout(statement, transactionTimeout);
// 设置读取条数
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 {
Integer queryTimeout = null;
// 获取超时时间
// 1.mapper.xml中设置
// 2.configuration文件中配置
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);
}
// 设置查询获取条数的多少
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);
}
}
// 关闭statement
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();
}
}
2.5PreparedStatementHandler
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);
}
// 初始化 Statement
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
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);
}
}
// parameterHandler设置jdbc sql参数
@Override
public void (Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
3.Statement处理流程
statementHandler完整执行流程。如下时序图:
总共执行过程分为三个阶段:
- 预处理:这里预处理不仅仅是通过Connection创建Statement,还包括设置参数。
- 执行:包含执行SQL和处理结果映射两部分。
- 关闭:直接关闭Statement。
erride
public void (Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
# 3.Statement处理流程
statementHandler完整执行流程。如下时序图:
[外链图片转存中...(img-N2THyCui-1632238789232)]
总共执行过程分为三个阶段:
1. 预处理:这里预处理不仅仅是通过Connection创建Statement,还包括设置参数。
2. 执行:包含执行SQL和处理结果映射两部分。
3. 关闭:直接关闭Statement。
参数处理和结果集封装,涉及数据库字段和JavaBean之间的相互映射,相对复杂。所以分别使用ParameterHandler与ResultSetHandler两个专门的组件实现。接下来就一起了解一下参数处理与结果集封装的处理流程。