670 lines
24 KiB
Markdown
670 lines
24 KiB
Markdown
# 精尽 MyBatis 源码分析 —— SQL 执行(二)之 StatementHandler
|
||
|
||
# 1. 概述
|
||
|
||
本文,我们来分享 SQL 执行的第二部分,`statement` 包。整体类图如下:[之 StatementHandler.assets/01.png)](http://static.iocoder.cn/images/MyBatis/2020_03_03/01.png)类图
|
||
|
||
- 我们可以看到,整体是以 StatementHandler 为核心。所以,本文主要会看到的就是 StatementHandler 对 JDBC Statement 的各种操作。
|
||
|
||
而 StatementHandler 在整个 SQL 执行过程中,所处的位置如下:[之 StatementHandler.assets/02.png)](http://static.iocoder.cn/images/MyBatis/2020_03_03/02.png)整体流程
|
||
|
||
# 2. StatementHandler
|
||
|
||
`org.apache.ibatis.executor.statement.StatementHandler` ,Statement 处理器,其中 Statement 包含 `java.sql.Statement`、`java.sql.PreparedStatement`、`java.sql.CallableStatement` 三种。代码如下:
|
||
|
||
```
|
||
// StatementHandler.java
|
||
|
||
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();
|
||
|
||
}
|
||
```
|
||
|
||
- 比较简单,胖友愁一愁。
|
||
|
||
StatementHandler 有多个子类,如下图所示:[](http://static.iocoder.cn/images/MyBatis/2020_03_03/03.png)类图
|
||
|
||
- 左边的三个实现类,分别对应 `java.sql.Statement`、`java.sql.PreparedStatement`、`java.sql.CallableStatement` 三种不同的实现类。
|
||
- 右边的 RoutingStatementHandler 实现类,负责将不同的 Statement 类型,路由到上述三个实现类上。
|
||
|
||
下面,我们先看右边的实现类,再看左边的实现类。
|
||
|
||
# 3. RoutingStatementHandler
|
||
|
||
`org.apache.ibatis.executor.statement.RoutingStatementHandler` ,实现 StatementHandler 接口,路由的 StatementHandler 对象,根据 Statement 类型,转发到对应的 StatementHandler 实现类中。
|
||
|
||
## 3.1 构造方法
|
||
|
||
```
|
||
// RoutingStatementHandler.java
|
||
|
||
/**
|
||
* 被委托的 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());
|
||
}
|
||
}
|
||
```
|
||
|
||
- 根据不同的类型,创建对应的 StatementHandler 实现类。
|
||
- 😈 经典的装饰器模式。实际上,有点多余。。。还不如改成工厂模式。
|
||
|
||
## 3.2 实现方法
|
||
|
||
所有的实现方法,调用 `delegate` 对应的方法即可。代码如下:
|
||
|
||
```
|
||
// RoutingStatementHandler.java
|
||
|
||
@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();
|
||
}
|
||
```
|
||
|
||
- 是不是更加觉得,换成工厂模式更合适。
|
||
|
||
# 4. BaseStatementHandler
|
||
|
||
`org.apache.ibatis.executor.statement.BaseStatementHandler` ,实现 StatementHandler 接口,StatementHandler 基类,提供骨架方法,从而使子类只要实现指定的几个抽象方法即可。
|
||
|
||
## 4.1 构造方法
|
||
|
||
```
|
||
// BaseStatementHandler.java
|
||
|
||
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) {
|
||
// 获得 Configuration 对象
|
||
this.configuration = mappedStatement.getConfiguration();
|
||
|
||
this.executor = executor;
|
||
this.mappedStatement = mappedStatement;
|
||
this.rowBounds = rowBounds;
|
||
|
||
// 获得 TypeHandlerRegistry 和 ObjectFactory 对象
|
||
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
|
||
this.objectFactory = configuration.getObjectFactory();
|
||
|
||
// <1> 如果 boundSql 为空,一般是写类操作,例如:insert、update、delete ,则先获得自增主键,然后再创建 BoundSql 对象
|
||
if (boundSql == null) { // issue #435, get the key before calculating the statement
|
||
// <1.1> 获得自增主键
|
||
generateKeys(parameterObject);
|
||
// <1.2> 创建 BoundSql 对象
|
||
boundSql = mappedStatement.getBoundSql(parameterObject);
|
||
}
|
||
this.boundSql = boundSql;
|
||
|
||
// <2> 创建 ParameterHandler 对象
|
||
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
|
||
// <3> 创建 ResultSetHandler 对象
|
||
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
|
||
}
|
||
```
|
||
|
||
- 大体是比较好理解的,我们就看几个点。
|
||
|
||
- `<1>` 处,如果 `boundSql` 为空:
|
||
|
||
- 一般是**写**类操作,例如:`insert`、`update`、`delete` 。代码如下:
|
||
|
||
```
|
||
// SimpleExecutor.java
|
||
|
||
@Override
|
||
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
|
||
Statement stmt = null;
|
||
try {
|
||
Configuration configuration = ms.getConfiguration();
|
||
// <x> 创建 StatementHandler 对象
|
||
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
|
||
// 初始化 StatementHandler 对象
|
||
stmt = prepareStatement(handler, ms.getStatementLog());
|
||
// 执行 StatementHandler ,进行写操作
|
||
return handler.update(stmt);
|
||
} finally {
|
||
// 关闭 StatementHandler 对象
|
||
closeStatement(stmt);
|
||
}
|
||
}
|
||
```
|
||
|
||
- `<x>` 处,调用 `Configuration#newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)` 方法,创建 StatementHandler 对象。其中,方法参数 `boundSql` 为 `null` 。
|
||
|
||
- `<1.1>` 处,调用 `#generateKeys(Object parameter)` 方法,获得自增主键。代码如下:
|
||
|
||
```
|
||
// BaseStatementHandler.java
|
||
|
||
protected void generateKeys(Object parameter) {
|
||
// 获得 KeyGenerator 对象
|
||
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
|
||
ErrorContext.instance().store();
|
||
// 前置处理,创建自增编号到 parameter 中
|
||
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
|
||
ErrorContext.instance().recall();
|
||
}
|
||
```
|
||
|
||
- 通过 KeyGenerator 对象,创建自增编号到 `parameter` 中。😈 详细的解析,见后续的 KeyGenerator 的内容。
|
||
|
||
- `<1.2>` 处,调用 `MappedStatement#getBoundSql(Object parameterObject)` 方法,创建 BoundSql 对象。
|
||
|
||
- 这个流程,可以调试下 `BindingTest#shouldInsertAuthorWithSelectKeyAndDynamicParams()` 单元测试方法。
|
||
|
||
- `<2>` 处,调用 `Configuration#newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql)` 方法,创建 ParameterHandler 对象。代码如下:
|
||
|
||
```
|
||
// Configuration.java
|
||
|
||
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
|
||
// 创建 ParameterHandler 对象
|
||
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
|
||
// 应用插件
|
||
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
|
||
return parameterHandler;
|
||
}
|
||
|
||
// XMLLanguageDriver.java
|
||
|
||
@Override
|
||
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
|
||
// 创建 DefaultParameterHandler 对象
|
||
return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
|
||
}
|
||
```
|
||
|
||
- 从代码中,可以看到,创建的是 DefaultParameterHandler 对象。而这个类,在 [《精尽 MyBatis 源码分析 —— SQL 初始化(下)之 SqlSource》](http://svip.iocoder.cn/MyBatis/scripting-2) 的 [「7.1 DefaultParameterHandler」](https://svip.iocoder.cn/MyBatis/executor-2/#) 已经有详细解析啦。
|
||
|
||
- `<3>` 处,创建 ResultSetHandler 对象。详细解析,见 [《精尽 MyBatis 源码分析 —— SQL 执行(四)之 ResultSetHandler》](http://svip.iocoder.cn/MyBatis/executor-4) 。
|
||
|
||
## 4.2 prepare
|
||
|
||
```
|
||
// BaseStatementHandler.java
|
||
|
||
@Override
|
||
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
|
||
ErrorContext.instance().sql(boundSql.getSql());
|
||
Statement statement = null;
|
||
try {
|
||
// <1> 创建 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);
|
||
}
|
||
}
|
||
```
|
||
|
||
- `<1>` 处,创建 `#instantiateStatement(Connection connection)` 方法,创建 Statement 对象。这是一个抽象方法,需要子类去实现。代码如下:
|
||
|
||
```
|
||
// BaseStatementHandler.java
|
||
|
||
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
|
||
```
|
||
|
||
- `<2>` 处,调用 `#setStatementTimeout(Statement stmt, Integer transactionTimeout)` 方法,设置超时时间。代码如下:
|
||
|
||
```
|
||
// BaseStatementHandler.java
|
||
|
||
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);
|
||
}
|
||
```
|
||
|
||
- `<3>` 处,设置 `fetchSize` 。代码如下:
|
||
|
||
```
|
||
// BaseStatementHandler.java
|
||
|
||
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);
|
||
}
|
||
}
|
||
```
|
||
|
||
- 感兴趣的胖友,可以看看 [《聊聊jdbc statement的fetchSize》](https://juejin.im/post/5a6757e351882573541c86bb) 和 [《正确使用MySQL JDBC setFetchSize()方法解决JDBC处理大结果集 java.lang.OutOfMemoryError: Java heap space》](https://blog.csdn.net/seven_3306/article/details/9303879) 。
|
||
|
||
# 5. SimpleStatementHandler
|
||
|
||
`org.apache.ibatis.executor.statement.SimpleStatementHandler` ,继承 BaseStatementHandler 抽象类,`java.sql.Statement` 的 StatementHandler 实现类。
|
||
|
||
## 5.1 构造方法
|
||
|
||
```
|
||
// SimpleStatementHandler.java
|
||
|
||
public SimpleStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
|
||
}
|
||
```
|
||
|
||
## 5.2 instantiateStatement
|
||
|
||
`#instantiateStatement()` 方法,创建 `java.sql.Statement` 对象。代码如下:
|
||
|
||
```
|
||
// SimpleStatementHandler.java
|
||
|
||
@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);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 5.3 parameterize
|
||
|
||
```
|
||
// SimpleStatementHandler.java
|
||
|
||
@Override
|
||
public void parameterize(Statement statement) throws SQLException {
|
||
// N/A
|
||
}
|
||
```
|
||
|
||
- 空,因为无需做占位符参数的处理。
|
||
|
||
## 5.4 query
|
||
|
||
```
|
||
// SimpleStatementHandler.java
|
||
|
||
@Override
|
||
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
|
||
String sql = boundSql.getSql();
|
||
// <1> 执行查询
|
||
statement.execute(sql);
|
||
// <2> 处理返回结果
|
||
return resultSetHandler.handleResultSets(statement);
|
||
}
|
||
```
|
||
|
||
- `<1>` 处,调用 `Statement#execute(String sql)` 方法,执行查询。
|
||
- `<2>` 处,调用 `ResultHandler#handleResultSets(Statement stmt)` 方法,处理返回结果。
|
||
|
||
## 5.5 queryCursor
|
||
|
||
```
|
||
// SimpleStatementHandler.java
|
||
|
||
@Override
|
||
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
|
||
String sql = boundSql.getSql();
|
||
// <1> 执行查询
|
||
statement.execute(sql);
|
||
// <2> 处理返回的 Cursor 结果
|
||
return resultSetHandler.handleCursorResultSets(statement);
|
||
}
|
||
```
|
||
|
||
- `<1>` 处,调用 `Statement#execute(String sql)` 方法,执行查询。
|
||
- `<2>` 处,调用 `ResultHandler#handleCursorResultSets(Statement stmt)` 方法,处理返回的 Cursor 结果。
|
||
|
||
## 5.6 batch
|
||
|
||
```
|
||
// SimpleStatementHandler.java
|
||
|
||
@Override
|
||
public void batch(Statement statement) throws SQLException {
|
||
String sql = boundSql.getSql();
|
||
// 添加到批处理
|
||
statement.addBatch(sql);
|
||
}
|
||
```
|
||
|
||
- 调用 `Statement#addBatch(String sql)` 方法,添加到批处理。
|
||
|
||
## 5.7 update
|
||
|
||
```
|
||
// SimpleStatementHandler.java
|
||
|
||
@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) {
|
||
// <1.1> 执行写操作
|
||
statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
|
||
// <2.2> 获得更新数量
|
||
rows = statement.getUpdateCount();
|
||
// <1.3> 执行 keyGenerator 的后置处理逻辑
|
||
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
|
||
// 如果是 SelectKeyGenerator 类型
|
||
} else if (keyGenerator instanceof SelectKeyGenerator) {
|
||
// <2.1> 执行写操作
|
||
statement.execute(sql);
|
||
// <2.2> 获得更新数量
|
||
rows = statement.getUpdateCount();
|
||
// <2.3> 执行 keyGenerator 的后置处理逻辑
|
||
keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);
|
||
} else {
|
||
// <3.1> 执行写操作
|
||
statement.execute(sql);
|
||
// <3.2> 获得更新数量
|
||
rows = statement.getUpdateCount();
|
||
}
|
||
return rows;
|
||
}
|
||
```
|
||
|
||
- 根据 `keyGenerator` 的类型,执行的逻辑,略有差异。
|
||
- `<1.1>`、`<1.2>`、`<1.3>` 处,调用 `Statement#execute(String sql, ...)` 方法,执行写操作。其中,`<1.1>` 比较特殊,使用数据自带的自增功能。
|
||
- `<1.2>`、`<2.2>`、`<3.2>` 处,调用 `Statement#getUpdateCount()` 方法,获得更新数量。
|
||
- `<1.3>`、`<2.3>` 处,调用 `KeyGenerator#processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter)` 方法,执行 `keyGenerator` 的后置处理逻辑。
|
||
- 虽然有点长,逻辑还是很清晰的。
|
||
|
||
# 6. PreparedStatementHandler
|
||
|
||
`org.apache.ibatis.executor.statement.PreparedStatementHandler` ,继承 BaseStatementHandler 抽象类,`java.sql.PreparedStatement` 的 StatementHandler 实现类。
|
||
|
||
## 6.1 构造方法
|
||
|
||
```
|
||
// PreparedStatementHandler.java
|
||
|
||
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
|
||
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
|
||
}
|
||
```
|
||
|
||
## 6.2 instantiateStatement
|
||
|
||
`#instantiateStatement()` 方法,创建 `java.sql.Statement` 对象。代码如下:
|
||
|
||
```
|
||
// PreparedStatementHandler.java
|
||
|
||
@Override
|
||
protected Statement instantiateStatement(Connection connection) throws SQLException {
|
||
String sql = boundSql.getSql();
|
||
// <1> 处理 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);
|
||
}
|
||
// <2>
|
||
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
|
||
return connection.prepareStatement(sql);
|
||
// <3>
|
||
} else {
|
||
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
|
||
}
|
||
}
|
||
```
|
||
|
||
- `<1>` 处,处理 Jdbc3KeyGenerator 的情况。
|
||
- `<2>` + `<3>` 处,和 SimpleStatementHandler 的方式是一致的。
|
||
|
||
## 6.3 parameterize
|
||
|
||
```
|
||
// PreparedStatementHandler.java
|
||
|
||
@Override
|
||
public void parameterize(Statement statement) throws SQLException {
|
||
parameterHandler.setParameters((PreparedStatement) statement);
|
||
}
|
||
```
|
||
|
||
- 调用 `ParameterHandler#setParameters(PreparedStatement ps)` 方法,设置 PreparedStatement 的占位符参数。
|
||
|
||
## 6.4 query
|
||
|
||
```
|
||
// PreparedStatementHandler.java
|
||
|
||
@Override
|
||
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
|
||
PreparedStatement ps = (PreparedStatement) statement;
|
||
// 执行查询
|
||
ps.execute();
|
||
// 处理返回结果
|
||
return resultSetHandler.handleResultSets(ps);
|
||
}
|
||
```
|
||
|
||
## 6.5 queryCursor
|
||
|
||
```
|
||
// PreparedStatementHandler.java
|
||
|
||
@Override
|
||
public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {
|
||
PreparedStatement ps = (PreparedStatement) statement;
|
||
// 执行查询
|
||
ps.execute();
|
||
// 处理返回的 Cursor 结果
|
||
return resultSetHandler.handleCursorResultSets(ps);
|
||
}
|
||
```
|
||
|
||
## 6.6 batch
|
||
|
||
```
|
||
// PreparedStatementHandler.java
|
||
|
||
@Override
|
||
public void batch(Statement statement) throws SQLException {
|
||
PreparedStatement ps = (PreparedStatement) statement;
|
||
// 添加到批处理
|
||
ps.addBatch();
|
||
}
|
||
```
|
||
|
||
## 6.7 update
|
||
|
||
```
|
||
// PreparedStatementHandler.java
|
||
|
||
@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;
|
||
}
|
||
```
|
||
|
||
# 7. CallableStatementHandler
|
||
|
||
`org.apache.ibatis.executor.statement.CallableStatementHandler` ,继承 BaseStatementHandler 抽象类,`java.sql.CallableStatement` 的 StatementHandler 实现类。
|
||
|
||
因为本系列不分享**存储过程**相关的内容,所以省略。感兴趣的胖友,自己研究哈。
|
||
|
||
# 8. 创建 StatementHandler 对象
|
||
|
||
在上面的文章中,我们已经看了各种 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>` 处,应用插件。关于**插件**,我们在后续的文章中,详细解析。
|
||
|
||
# 666. 彩蛋
|
||
|
||
比较简单,都是咱们熟悉的 Statement 的方法封装。
|
||
|
||
参考和推荐如下文章:
|
||
|
||
- 祖大俊 [《Mybatis3.3.x技术内幕(六):StatementHandler(Box stop here)》](https://my.oschina.net/zudajun/blog/668378)
|
||
- 徐郡明 [《MyBatis 技术内幕》](https://item.jd.com/12125531.html) 的 [「3.5 StatementHandler](https://svip.iocoder.cn/MyBatis/executor-2/#) 小节 |