part3-simple-executor-sql-execution
约 3930 字大约 13 分钟
2026-05-24
系列文章:《深入Spring事务与数据源:从注解到数据库连接的全链路解析》
系列三第3篇:SimpleExecutor执行SQL完整源码解析
基于版本:MyBatis 3.5.x、Spring Framework 5.3.x
前置阅读:系列三第2篇:SqlSession与Executor执行器的创建
前言
上一篇文章咱们把SqlSession和Executor的创建流程搞清楚了,知道了MyBatis是怎么创建会话、怎么创建执行器的。
但是,Executor具体是怎么执行SQL的?这个问题咱们还没深入。
你可能每天都在用:
User user = userMapper.selectById(1);但是,这行代码背后,Executor干了啥?
- SimpleExecutor的doQuery是怎么实现的?
- Statement是怎么创建的?
- SQL参数是怎么设置的?
- 结果集是怎么映射的?
别急,今天这篇文章就来回答这些问题。而且我敢说,搞懂了SimpleExecutor的执行流程,你对MyBatis的理解就能超过85%的Java开发!
好了,废话不多说,开干!
一、回顾一下:Spring Boot是怎么配置MyBatis的?
老规矩,快速回顾一下自动装配的入口。
核心入口:MybatisAutoConfiguration
文件位置:mybatis-spring-boot-autoconfigure/MybatisAutoConfiguration.java
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);
// ... 其他配置
return factoryBean.getObject();
}这个配置创建了SqlSessionFactory,然后就能创建SqlSession,然后就能获取Executor。
好了,回顾完毕,正式进入咱们的主题!
二、SimpleExecutor:最简单的执行器
好,现在来看SimpleExecutor的源码。
核心类1:SimpleExecutor
文件位置:mybatis-3/SimpleExecutor.java
package org.apache.ibatis.executor;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* 简单执行器
* 每次执行SQL都创建新的Statement对象
* 执行完就关闭
*/
public class SimpleExecutor extends BaseExecutor {
public SimpleExecutor(Configuration config, Transaction transaction) {
super(config, transaction);
}
@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
// ========== 第一步:获取Configuration ==========
Configuration configuration = ms.getConfiguration();
// ========== 第二步:创建StatementHandler ==========
// ★★★★★ 核心:创建StatementHandler ★★★★★
StatementHandler handler = configuration.newStatementHandler(
this, ms, parameter, RowBounds.DEFAULT, null, null);
// ========== 第三步:准备Statement ==========
// ★★★★★ 核心:创建Statement并设置参数 ★★★★★
stmt = prepareStatement(handler, ms.getStatementLog());
// ========== 第四步:执行SQL ==========
// ★★★★★ 核心:调用StatementHandler.update()执行SQL ★★★★★
return handler.update(stmt);
} finally {
// ========== 第五步:关闭Statement ==========
closeStatement(stmt);
}
}
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
// ========== 第一步:获取Configuration ==========
Configuration configuration = ms.getConfiguration();
// ========== 第二步:创建StatementHandler ==========
// ★★★★★ 核心:创建StatementHandler ★★★★★
StatementHandler handler = configuration.newStatementHandler(
wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// ========== 第三步:准备Statement ==========
// ★★★★★ 核心:创建Statement并设置参数 ★★★★★
stmt = prepareStatement(handler, ms.getStatementLog());
// ========== 第四步:执行查询 ==========
// ★★★★★ 核心:调用StatementHandler.query()执行查询 ★★★★★
return handler.query(stmt, resultHandler);
} finally {
// ========== 第五步:关闭Statement ==========
closeStatement(stmt);
}
}
@Override
public <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds,
BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(
wrapper, ms, parameter, rowBounds, null, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.queryCursor(stmt);
} finally {
closeStatement(stmt);
}
}
@Override
public List<BatchResult> doFlushStatements(boolean isRollback) {
// SimpleExecutor不支持批量操作
return null;
}
/**
* 准备Statement
*/
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// ========== 第一步:获取数据库连接 ==========
// ★★★★★ 核心:从Transaction获取Connection ★★★★★
Connection connection = getConnection(statementLog);
// ========== 第二步:创建Statement ==========
// ★★★★★ 核心:调用StatementHandler.prepare()创建Statement ★★★★★
stmt = handler.prepare(connection, transaction.getTimeout());
// ========== 第三步:设置参数 ==========
// ★★★★★ 核心:调用StatementHandler.parameterize()设置参数 ★★★★★
handler.parameterize(stmt);
return stmt;
}
}看到了吧?SimpleExecutor的执行流程特别清晰:
查询流程:
- 创建StatementHandler
- 准备Statement(获取连接、创建Statement、设置参数)
- 执行查询(调用StatementHandler.query())
- 关闭Statement
更新流程:
- 创建StatementHandler
- 准备Statement(获取连接、创建Statement、设置参数)
- 执行更新(调用StatementHandler.update())
- 关闭Statement
关键点:所有的核心逻辑都委托给了StatementHandler!
这就是经典的委托模式!
三、StatementHandler:Statement的处理器
好,现在来看StatementHandler是怎么工作的。
核心接口1:StatementHandler
文件位置:mybatis-3/StatementHandler.java
package org.apache.ibatis.executor.statement;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* Statement处理器
* 负责创建Statement、设置参数、执行SQL、处理结果
*/
public interface StatementHandler {
/**
* 准备Statement
*/
Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException;
/**
* 设置参数
*/
void parameterize(Statement statement) throws SQLException;
/**
* 批量执行
*/
void batch(Statement statement) throws SQLException;
/**
* 执行更新
*/
int update(Statement statement) throws SQLException;
/**
* 执行查询
*/
<E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException;
/**
* 获取BoundSql
*/
BoundSql getBoundSql();
/**
* 获取ParameterHandler
*/
ParameterHandler getParameterHandler();
}StatementHandler接口定义了5个核心方法:
prepare():创建Statementparameterize():设置参数batch():批量执行update():执行更新query():执行查询
四、BaseStatementHandler:StatementHandler的抽象基类
好,现在来看StatementHandler的抽象基类——BaseStatementHandler。
核心类2:BaseStatementHandler
文件位置:mybatis-3/BaseStatementHandler.java
package org.apache.ibatis.executor.statement;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* StatementHandler的抽象基类
* 实现了prepare()方法
*/
public abstract class BaseStatementHandler implements StatementHandler {
// Configuration配置
protected final Configuration configuration;
// 对象工厂
protected final ObjectFactory objectFactory;
// 类型处理器注册表
protected final TypeHandlerRegistry typeHandlerRegistry;
// 结果处理器
protected final ResultSetHandler resultSetHandler;
// ★★★★★ 核心:参数处理器 ★★★★★
protected final ParameterHandler parameterHandler;
// 执行器
protected final Executor executor;
// MappedStatement
protected final MappedStatement mappedStatement;
// 行边界
protected final RowBounds rowBounds;
// ★★★★★ 核心:BoundSql(包含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) {
// 生成BoundSql
generateKeys(parameterObject);
this.boundSql = mappedStatement.getBoundSql(parameterObject);
} else {
this.boundSql = boundSql;
}
// ★★★★★ 核心:创建参数处理器 ★★★★★
this.parameterHandler = configuration.newParameterHandler(
mappedStatement, parameterObject, boundSql);
// ★★★★★ 核心:创建结果处理器 ★★★★★
this.resultSetHandler = configuration.newResultSetHandler(
executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(mappedStatement.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);
}
}
/**
* 实例化Statement(子类实现)
*/
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
@Override
public void parameterize(Statement statement) throws SQLException {
// ★★★★★ 核心:调用参数处理器设置参数 ★★★★★
parameterHandler.setParameters((PreparedStatement) statement);
}
@Override
public int update(Statement statement) throws SQLException {
// 转换为PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
// ★★★★★ 核心:执行SQL ★★★★★
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 <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
// 转换为PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
// ★★★★★ 核心:执行SQL并处理结果集 ★★★★★
ps.execute();
// 调用结果处理器处理结果
return resultSetHandler.handleResultSets(ps);
}
}看到了吧?BaseStatementHandler也用了模板方法模式!
它实现了prepare()、parameterize()、update()、query()等通用逻辑,但是把instantiateStatement()留给子类实现。
关键点1:prepare()方法
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) {
// 调用子类实现
statement = instantiateStatement(connection);
// 设置超时
setStatementTimeout(statement, transactionTimeout);
// 设置fetchSize
setFetchSize(statement);
return statement;
}关键点2:parameterize()方法
@Override
public void parameterize(Statement statement) {
// 调用参数处理器设置参数
parameterHandler.setParameters((PreparedStatement) statement);
}关键点3:query()方法
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) {
// 执行SQL
ps.execute();
// 处理结果集
return resultSetHandler.handleResultSets(ps);
}看到了吗?查询的核心逻辑是:
- 执行SQL(
ps.execute()) - 处理结果集(
resultSetHandler.handleResultSets())
五、PreparedStatementHandler:最常用的StatementHandler
好,现在来看最常用的StatementHandler实现——PreparedStatementHandler。
核心类3:PreparedStatementHandler
文件位置:mybatis-3/PreparedStatementHandler.java
package org.apache.ibatis.executor.statement;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* PreparedStatement处理器
* 使用PreparedStatement执行SQL
*/
public class PreparedStatementHandler extends BaseStatementHandler {
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement,
Object parameterObject, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
// 获取SQL
String sql = boundSql.getSql();
// ★★★★★ 核心:创建PreparedStatement ★★★★★
if (mappedStatement.getKeyGenerator() != null &&
mappedStatement.getKeyColumns() != null) {
// 如果有自增主键,需要返回生成的键
String[] keyColumns = mappedStatement.getKeyColumns();
return connection.prepareStatement(sql, keyColumns);
} else {
// 普通PreparedStatement
return connection.prepareStatement(sql);
}
}
@Override
public void parameterize(Statement statement) throws SQLException {
// ★★★★★ 核心:调用参数处理器设置参数 ★★★★★
parameterHandler.setParameters((PreparedStatement) statement);
}
@Override
public int update(Statement statement) throws SQLException {
// 转换为PreparedStatement
PreparedStatement ps = (PreparedStatement) statement;
// 执行SQL
ps.execute();
// 获取影响行数
int rows = ps.getUpdateCount();
// 获取参数对象
Object parameterObject = boundSql.getParameterObject();
// 处理自增主键
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 执行SQL
ps.execute();
// ★★★★★ 核心:处理结果集 ★★★★★
return resultSetHandler.handleResultSets(ps);
}
}看到了吧?PreparedStatementHandler的核心就是:
- 创建PreparedStatement(
instantiateStatement()) - 设置参数(
parameterize(),委托给ParameterHandler) - 执行SQL(
ps.execute()) - 处理结果集(委托给ResultSetHandler)
六、ParameterHandler:参数处理器
好,现在来看参数是怎么设置的。
核心接口2:ParameterHandler
文件位置:mybatis-3/ParameterHandler.java
package org.apache.ibatis.executor.parameter;
import org.apache.ibatis.mapping.BoundSql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* 参数处理器
* 负责设置SQL参数
*/
public interface ParameterHandler {
/**
* 获取参数对象
*/
Object getParameterObject();
/**
* 设置参数
*/
void setParameters(PreparedStatement ps) throws SQLException;
}接口很简单,就一个核心方法:setParameters()。
核心类4:DefaultParameterHandler
文件位置:mybatis-3/DefaultParameterHandler.java
package org.apache.ibatis.executor.parameter;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeException;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
/**
* 默认参数处理器
*/
public class DefaultParameterHandler implements ParameterHandler {
// 类型处理器注册表
private final TypeHandlerRegistry typeHandlerRegistry;
// MappedStatement
private final MappedStatement mappedStatement;
// 参数对象
private final Object parameterObject;
// ★★★★★ 核心:BoundSql(包含参数映射)★★★★★
private final BoundSql boundSql;
// Configuration
private final Configuration configuration;
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters")
.object(mappedStatement.getParameterMap().getId());
// ========== 第一步:获取参数映射列表 ==========
// ★★★★★ 核心:获取ParameterMapping列表 ★★★★★
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
// ========== 第二步:遍历所有参数映射 ==========
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
// 如果是输出参数,跳过
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
// ========== 第三步:获取参数值 ==========
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
// 从附加参数获取
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
// 参数对象为null
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
// 参数对象本身就是基本类型
value = parameterObject;
} else {
// 从参数对象的属性获取
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// ========== 第四步:获取类型处理器 ==========
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// ★★★★★ 核心:调用类型处理器设置参数 ★★★★★
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " +
parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " +
parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}看到了吧?setParameters()方法做了4件事:
- 获取参数映射列表(从BoundSql)
- 遍历所有参数映射
- 获取参数值(从参数对象)
- 调用类型处理器设置参数
关键点:类型处理器的作用
// 获取类型处理器
TypeHandler typeHandler = parameterMapping.getTypeHandler();
// 设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);类型处理器负责将Java类型转换为JDBC类型。
扩展场景1:常用的类型处理器
// Integer类型
public class IntegerTypeHandler extends BaseTypeHandler<Integer> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType) {
ps.setInt(i, parameter);
}
}
// String类型
public class StringTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) {
ps.setString(i, parameter);
}
}
// Date类型
public class DateTypeHandler extends BaseTypeHandler<Date> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) {
ps.setDate(i, new java.sql.Date(parameter.getTime()));
}
}七、ResultSetHandler:结果集处理器
好,现在来看结果集是怎么处理的。
核心接口3:ResultSetHandler
文件位置:mybatis-3/ResultSetHandler.java
package org.apache.ibatis.executor.resultset;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* 结果集处理器
* 负责处理ResultSet
*/
public interface ResultSetHandler {
/**
* 处理结果集
*/
<E> List<E> handleResultSets(Statement stmt) throws SQLException;
/**
* 处理输出参数
*/
void handleOutputParameters(CallableStatement cs) throws SQLException;
}接口也很简单,核心就是handleResultSets()。
核心类5:DefaultResultSetHandler
文件位置:mybatis-3/DefaultResultSetHandler.java
package org.apache.ibatis.executor.resultset;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandler;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* 默认结果集处理器
*/
public class DefaultResultSetHandler implements ResultSetHandler {
// 配置对象
private final Configuration configuration;
// 执行器
private final Executor executor;
// MappedStatement
private final MappedStatement mappedStatement;
// 行边界
private final RowBounds rowBounds;
// 参数处理器
private final ParameterHandler parameterHandler;
// 结果处理器
private final ResultHandler<?> resultHandler;
// BoundSql
private final BoundSql boundSql;
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
// ========== 第一步:创建结果列表 ==========
final List<Object> multipleResults = new ArrayList<>();
int resultSetCount = 0;
// ========== 第二步:获取第一个ResultSet ==========
ResultSetWrapper rsw = getFirstResultSet(stmt);
// ========== 第三步:获取ResultMap ==========
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
// ========== 第四步:处理ResultSet ==========
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
// ★★★★★ 核心:处理ResultSet,将结果放入multipleResults ★★★★★
handleResultSet(rsw, resultMap, multipleResults, null);
// 获取下一个ResultSet
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
// ========== 第五步:返回结果 ==========
return collapseSingleResultList(multipleResults);
}
/**
* 处理单个ResultSet
*/
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap,
List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {
try {
if (parentMapping != null) {
// 处理嵌套结果
handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
} else {
if (resultHandler == null) {
// 创建默认结果处理器
ResultHandler<?> defaultResultHandler = new DefaultResultHandler();
// ★★★★★ 核心:处理行数据 ★★★★★
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
// 将结果添加到列表
multipleResults.addAll(defaultResultHandler.getResultList());
} else {
// 使用自定义结果处理器
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
// 关闭ResultSet
closeResultSet(rsw.getResultSet());
}
}
/**
* 处理行数据
*/
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap,
ResultHandler<?> resultHandler, RowBounds rowBounds,
ResultMapping parentMapping) throws SQLException {
if (resultMap.hasNestedResultMaps()) {
// 处理嵌套结果映射
ensureNoRowBounds();
checkResultHandler();
handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds);
} else {
// ★★★★★ 核心:处理简单结果映射 ★★★★★
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
/**
* 处理简单结果映射
*/
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
ResultHandler<?> resultHandler, RowBounds rowBounds,
ResultMapping parentMapping) throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
// 跳过前面的行(分页)
skipRows(rsw.getResultSet(), rowBounds);
// ========== 遍历所有行 ==========
while (shouldProcessMoreRows(resultContext, rowBounds)
&& rsw.getResultSet().next()) {
// ========== 第一步:获取ResultMap ==========
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(
rsw.getResultSet(), resultMap, null);
// ========== 第二步:创建结果对象 ==========
// ★★★★★ 核心:从ResultSet创建Java对象 ★★★★★
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
// ========== 第三步:存储对象 ==========
storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());
}
}
/**
* 从ResultSet获取行值
*/
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
// ========== 第一步:创建结果对象 ==========
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
// ★★★★★ 核心:创建结果对象(使用ObjectFactory)★★★★★
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
// ========== 第二步:设置属性值 ==========
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = !resultMap.getResultMappings().isEmpty();
if (shouldApplyAutomaticMappings(resultMap, false)) {
// 自动映射
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
// 手动映射
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
// 如果找到值,返回对象
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
}看到了吧?结果集处理的流程是:
- 获取ResultSet
- 获取ResultMap
- 处理每一行(
handleRowValues()) - 创建结果对象(
getRowValue()) - 设置属性值(
applyAutomaticMappings()或applyPropertyMappings()) - 返回结果列表
关键点:自动映射
// 自动映射(下划线转驼峰)
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
}这就是为什么配置了map-underscore-to-camel-case: true后,数据库的user_name会自动映射到Java的userName!
八、完整的SQL执行流程图
说了这么多,咱们画个图把整个流程串起来:
调用:userMapper.selectById(1)
↓
┌──────────────────────────────────────────┐
│ MapperProxy.invoke() │
│ → MapperMethod.execute() │
│ → sqlSession.selectOne() │
└─────────────┬────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ DefaultSqlSession.selectOne() │
│ → selectList() │
│ → executor.query() │
└─────────────┬────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ BaseExecutor.query() │
│ │
│ 1. 创建CacheKey │
│ 2. 从一级缓存获取 │
│ → 命中:返回缓存 │
│ → 未命中:queryFromDatabase() │
└─────────────┬────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ BaseExecutor.queryFromDatabase() │
│ → SimpleExecutor.doQuery() │
│ │
│ 1. 创建StatementHandler │
│ → PreparedStatementHandler │
│ │
│ 2. prepareStatement() │
│ → getConnection() │
│ → handler.prepare() │
│ → instantiateStatement() │
│ → connection.prepareStatement() │
│ → handler.parameterize() │
│ → parameterHandler.setParameters() │
│ → typeHandler.setParameter() │
│ │
│ 3. handler.query() │
│ → ps.execute() │
│ → resultSetHandler.handleResultSets() │
│ → handleResultSet() │
│ → handleRowValues() │
│ → getRowValue() │
│ → createResultObject() │
│ → applyAutomaticMappings() │
│ → applyPropertyMappings() │
│ │
│ 4. 放入一级缓存 │
│ 5. 返回结果 │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ 关闭Statement │
│ 返回结果 │
└──────────────────────────────────────────┘九、关键问题解答
Q1:SimpleExecutor和ReuseExecutor的区别是什么?
答案:SimpleExecutor每次创建新Statement,ReuseExecutor复用Statement。
Q2:参数是怎么设置的?
答案:通过ParameterHandler.setParameters(),遍历ParameterMapping,调用TypeHandler.setParameter()设置。
Q3:结果集是怎么映射的?
答案:通过ResultSetHandler.handleResultSets(),创建结果对象,然后应用自动映射或手动映射。
Q4:一级缓存什么时候生效?
答案:同一个SqlSession内,相同的查询(相同的CacheKey)会命中缓存。
十、总结与伏笔
通过这篇文章的分析,咱们搞清楚了SimpleExecutor执行SQL的完整流程:
- SimpleExecutor:委托给StatementHandler执行
- BaseStatementHandler:模板方法模式,实现通用逻辑
- PreparedStatementHandler:创建PreparedStatement
- ParameterHandler:设置SQL参数
- TypeHandler:Java类型转JDBC类型
- ResultSetHandler:处理结果集
- 自动映射:下划线转驼峰
整个流程就是:
创建StatementHandler → 创建Statement → 设置参数 → 执行SQL → 处理结果集 → 返回结果下一篇文章,咱们会继续深入MyBatis的其他核心机制,包括批量执行器、缓存机制等。
敬请期待!
参考资料
- MyBatis 3.5.x 源码
src/main/java/org/apache/ibatis/executor/SimpleExecutor.javasrc/main/java/org/apache/ibatis/executor/statement/BaseStatementHandler.javasrc/main/java/org/apache/ibatis/executor/statement/PreparedStatementHandler.javasrc/main/java/org/apache/ibatis/executor/parameter/DefaultParameterHandler.javasrc/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
- 《MyBatis技术内幕》