StatementHandler
- Statement 是 java.sql 包中的一个类,主要用于 sql 语句的执行和 sql 执行返回结果的处理。
- StatementHandler 是对 Statement 的一个封装,提供了 Statement 的所有功能,使 Mybatis 使用 Statement 对象更方便、快捷。
- 提供了 创建 Statement 对象,绑定执行的实参,批量执行 Sql语句,执行 select、update、delete、insert 语句功能,还有将结果集映射为成结果对象。
StatementHandler 依赖 ParameterHandler 和 ResultSetHandler
完成了 Mybatis 的核心功能,它控制着参数绑定、 SQL 语句执行、结果集映射等一系列核心过程。
StatementHandler 是一个接口,定义了一些规范,有四个实现类,定义了具体的实现。
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;
// 执行 select 语句
<E> Cursor<E> queryCursor(Statement statement)
throws SQLException;
BoundSql getBoundSql();
// 获取 ParameterHandler 对象
ParameterHandler getParameterHandler();
}
UML 类图
image.pngRoutingStatementHandler
RoutingStatementHandler 会根据 MappedStatement 指定的 statementType 宇段,创建对应的 StatementHandler 接口实现。
定义一个 StatementHandler 接口 代理对象,根据 statementType 类型,创建 StatementHandler 接口具体实现,有点像策略模式。
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());
}
}
}
BaseStatementHandler
BaseStatementHandler 是 StatementHandler 的一个抽象类定义了各个 StatementHandler 接口集体实现的公共成员。
public abstract class BaseStatementHandler implements StatementHandler {
protected final Configuration configuration;
// 对象工厂,创建对象来使用
protected final ObjectFactory objectFactory;
// 类型转换注册器
protected final TypeHandlerRegistry typeHandlerRegistry;
// SQL 查询结果,封装成 ResultMap 对象 处理器
protected final ResultSetHandler resultSetHandler;
// 记录使用的 ParameterHandler 对象, ParameterHandler 的主要功能是为 SQL 句绑定实参 ,使用实参替换 SQL 吾句的中 ? 占位符。
protected final ParameterHandler parameterHandler;
// sql 执行器
protected final Executor executor;
// 封装 mapper.xml <SQL> 节点 成 MappedStatement 对象
protected final MappedStatement mappedStatement;
// RowBounds 记录了用户设置的 offset limit ,用于在结采集中定位映射的起始位置和结束位置
protected final RowBounds rowBounds;
// 数据库可以执行的 SQL 语句
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
// 调用 KeyGenerator processBefore() 方法获取主键
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);
}
}
SimpleStatementHandler
SimpleStatementHandler 继承了 BaseStatementHandler 抽象类。它底层使用 java.sql.Statement 对象来完成数据库的相关操作。所以 SQL 语句中不能存在占位符,相应的,SimpleStatementHandler.parameterize() 方法是空实现。
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 {
//获取 SQL 语句
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();
// 将数据库生成的主键添加到 parameterObject 中
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else if (keyGenerator instanceof SelectKeyGenerator) {
statement.execute(sql);
rows = statement.getUpdateCount();
// 执行 <selectKey> 节点中配置的 SQL 语句获取数据库生成的主键,并添加到 parameterObject 中
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
} else {
// update、delete 语句
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 {
// 获取 SQL 语句
String sql = boundSql.getSql();
// 调用 Statement.executor()方法执行 SQL 语句
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);
}
/**
* instantiateStatement 方法直接通过 JDB Connection 创建 statement 对象
* @param connection
* @return
* @throws SQLException
*/
@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) {
// N/A
}
}
PreparedStatementHandler
PreparedStatementHandler 底层依赖于 java.sq1.PreparedStatement 象来完成数据库的相关操。
在 SimpleStatementHandler.parameterize() 方法中, 会调用前面介绍的 ParameterHandler.setParameters() 方法完成 SQL 语句的参数绑定。
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);
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
//获取待执行的 SQL 语句
String sql = boundSql.getSql();
//根据 MappedStatement.keyGenerator 字段的位,创建 PreparedStatement 对象
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); // 返回数据库生成的主键
} else {
// 在 insert 语句执行完成之后,会将 keyColumn 指定的列对象
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
//创建普通的 PreparedStatement 对象
return connection.prepareStatement(sql);
} else {
//设置结果集是否可以滚动以及其游标是否可以上下移动,设置结采集是否可更新
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
CallableStatementHandler
CallableStatementHndler 底层依赖于 java.sql.CallableStatement 调用存储过程,其中 parameterize()方法也会调用 ParameterHandler.setParameters()方法完 SQL 语句参数绑定,并指定输出参数的索引位置和 JDBC 类型。
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 {
return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
@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) {
if (null == parameterMapping.getJdbcType()) {
throw new ExecutorException("The JDBC Type must be specified for output parameter. Parameter: " + parameterMapping.getProperty());
} else {
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());
}
}
}
}
}
}
}
网友评论