SqlSession 执行主流程
获取 BoundSql
- 经过加载完所有配置之后,继续梳理执行 sql 的过程
public class MybatisTest {
@Test
public void test1() throws IOException {
...
User user = sqlSession.selectOne("user.findUserById", 1);
...
}
}
- 当调用 selectOne() 时,底层将会调用的是 selectOne(java.lang.String, java.lang.Object)
public class DefaultSqlSession implements SqlSession {
...
@Override
public <T> T selectOne(String statement, Object parameter) {
List<T> list = this.selectList(statement, parameter);
...
}
}
- 继续调用时,会先装入默认的分页器 RowBounds,然后继续调用重载的 selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds)
public class DefaultSqlSession implements SqlSession {
...
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
}
- 继续调用,也会装入空的 ResultHandler,继续调用重载的 selectList(java.lang.String, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)
public class DefaultSqlSession implements SqlSession {
...
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
}
}
- 通过传入 statementId 即 “user.findUserById”,然后 configuration 对象拿到 MappedStatement 对象,然后利用执行器来执行查询
public class DefaultSqlSession implements SqlSession {
...
private final Configuration configuration;
private final Executor executor;
...
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
...
MappedStatement ms = configuration.getMappedStatement(statement);
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
}
}
- 在执行器执行的查询时,是调用经过封装后的 CachingExecutor 的 query() 方法。该方法会从 MappedStatement 对象中拿到对应的 BoundSql 对象
public class CachingExecutor implements Executor {
...
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
...
}
}
- 其中,MappedStatement 对象会将参数 parameterObject 传入,然后委托 SqlSource 来获取 BoundSql,从上面的流程下来是不涉及动态 sql,所以这个 SqlSource 为 StaticSqlSource
public final class MappedStatement {
...
private SqlSource sqlSource;
...
public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
...
}
}
- StaticSqlSource 会把 configuration、sql、parameterMappings、parameterObject 对象封装到 BoundSql 内并且返回
public class StaticSqlSource implements SqlSource {
private final String sql;
private final List<ParameterMapping> parameterMappings;
private final Configuration configuration;
@Override
public BoundSql getBoundSql(Object parameterObject) {
return new BoundSql(configuration, sql, parameterMappings, parameterObject);
}
}
- 拿到 BoundSql 后,先检查参数是不是一个对象映射,需要获取参数对应的映射位,但是现在的映射文件的 sql 输入只是个整形,所以这里执行是空,最后 MappedStatement 对象直接返回 BoundSql 对象,然后 CachingExecutor 就拿到对应的 BoundSql
public final class MappedStatement {
...
private SqlSource sqlSource;
...
public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
...
}
return boundSql;
}
}
- 总结
生成 CacheKey
- 问题
- CacheKey 是由几部分构成的,怎么生成的?
- 怎么完成的 CacheKey 比较,怎么保证 CacheKey 的唯一性?
- 对于 SqlSession 而言,它会把实际执行交给 Executor,而我们知道在 MyBatis 中会话级别是有缓存的,那么这个缓存 Key 是怎么构造,就是在 CachingExecutor 当中,根据 MappedStatement、parameterObject 实际参数、rowBounds 分页对象以及 BoundSql 来构造的
public class CachingExecutor implements Executor {
...
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
BoundSql boundSql = ms.getBoundSql(parameterObject);
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
...
}
}
- 在 CachingExecutor 中,它会委派 SimpleExecutor 来创建缓存建
public class CachingExecutor implements Executor {
private final Executor delegate;
...
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
return delegate.createCacheKey(ms, parameterObject, rowBounds, boundSql);
}
}
- SimpleExecutor 首先会创建一个 CacheKey 对象,这个对象会初始化各种算子参数,用于后面的缓存计算,缓存 Key 的组成部分如下
public class CacheKey implements Cloneable, Serializable {
private static final int DEFAULT_MULTIPLIER = 37;
private static final int DEFAULT_HASHCODE = 17;
...
private final int multiplier;
private int hashcode;
private long checksum;
private int count;
private List<Object> updateList;
public CacheKey() {
this.hashcode = DEFAULT_HASHCODE;
this.multiplier = DEFAULT_MULTIPLIER;
this.count = 0;
this.updateList = new ArrayList<>();
}
}
- 回到 SimpleExecutor,它其实调用的是父类 BaseExecutor 的 createCacheKey() 方法,会根据 MappedStatement、parameterObject 实际参数、rowBounds 分页对象以及 BoundSql 来计算 CacheKey 内的哈希值
public abstract class BaseExecutor implements Executor {
...
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
cacheKey.update(value);
}
}
if (configuration.getEnvironment() != null) {
cacheKey.update(configuration.getEnvironment().getId());
}
return cacheKey;
}
}
- 其中 CacheKey 的 update() 方法会把输入的各种参数计算一次哈希,然后把值也存到里面去
public class CacheKey implements Cloneable, Serializable {
...
public void update(Object object) {
int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);
count++;
checksum += baseHashCode;
baseHashCode *= count;
hashcode = multiplier * hashcode + baseHashCode;
updateList.add(object);
}
}
- 生成的哈希值如下
- 总结
- 最后生成的 Key 找缓存值流程如下
- 生成 CacheKey 流程
缓存优先级
- 问题
- 如果开启了一二级缓存,究竟是调用一级缓存优先还是二级缓存?
- 首先配置文件中,开启二级缓存
<mapper namespace="user">
<cache>cache>
...
mapper>
- 拿到 CacheKey、parameterObject、MappedStatement、BoundSql、RowBounds 时候,开始执行真正的查询
public class CachingExecutor implements Executor {
...
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
...
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
}
- query() 方法
- 首先会从 MappedStatement 拿到二级缓存,然后检查对应的 sql 是否配置了
flushCache=true
,是的话,先把二级缓存清空了
- 然后判断对应语句是否使用缓存
useCache
,默认是开启的
- 然后根据 StatementType 确定是否处理出参参数,这里是 PREPARED 类型,不是存储过程(CALLABLE 类型),所以不处理
- 再从二级缓存中查询数据,没有委托给 SimpleExecutor 查询一级缓存和数据库,最后把查出来的数据放回到二级缓存(暂时是存到 map 集合,实际还没存到二级缓存)
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
...
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list);
}
return list;
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
}
- 委托给 SimpleExecutor 父类的 query() 方法
- 首先判断 sql 是否配置了
flushCacheRequired
,是的话会在执行器执行之前,清空本地以及缓存
- 然后从一级缓存中获取数据
- 如果有缓存结果,再判断是否是存储过程类型(CALLABLE 类型),是的话处理输出参数,否则的话直接从数据库里面查询结果
public abstract class BaseExecutor implements Executor {
protected PerpetualCache localCache;
...
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
...
}
}
- 总结
StatementHandler 预处理得到 Statement 对象
- SimpleExecutor 从缓存中拿不到到数据,就需要从 db 中获取
public abstract class BaseExecutor implements Executor {
...
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
...
try {
...
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
}
}
- 然后执行 SimpleExecutor 的 doQuery(),这是由 SimpleExecutor 实现的。其中查询前会在本地缓存中,添加占位符,拿到数据后再移除
public abstract class BaseExecutor implements Executor {
...
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
localCache.removeObject(key);
}
localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
}
- SimpleExecutor 先从 MappedStatement 拿到 Configuration 对象,然后通过 Configuration 对象创建 StatementHandler 语句处理器
public class SimpleExecutor extends BaseExecutor {
protected Executor wrapper;
...
@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();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
...
} finally {
closeStatement(stmt);
}
}
}
- StatementHandler 创建很关键,它会先通过 RoutingStatementHandler 以及插件拦截装饰后返回 StatementHandler 对象
- 【重点】: 这里的插件机制是 MyBatis 扩展的关键地方之一
public class Configuration {
...
protected final InterceptorChain interceptorChain = new InterceptorChain();
...
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
}
- 其中 StatementHandler 组织如下
- BaseStatementHandler: 基础语句处理器(抽象类),它基本把语句处理器接口的核心部分都实现了,包括配置绑定、执行器绑定、映射器绑定、参数处理器构建、结果集处理器构建、语句超时设置、语句关闭等,并另外定义了新的方法 instantiateStatement() 供不同子类实现以便获取不同类型的语句连接,子类可以普通执行 SQL 语句,也可以做预编译执行,还可以执行存储过程等
- SimpleStatementHandler:普通语句处理器,继承 BaseStatementHandler 抽象类,对应 java.sql.Statement 对象的处理,处理普通的不带动态参数运行的 SQL,即执行简单拼接的字符串语句,同时由于 Statement 的特性,SimpleStatementHandler 每次执行都需要编译 SQL (注意:我们知道 SQL 的执行是需要编译和解析的)
- PreparedStatementHandler:预编译语句处理器,继承 BaseStatementHandler 抽象类,对应 java.sql.PrepareStatement 对象的处理,相比上面的普通语句处理器,它支持可变参数 SQL 执行,由于 PrepareStatement 的特性,它会进行预编译,在缓存中一旦发现有预编译的命令,会直接解析执行,所以减少了再次编译环节,能够有效提高系统性能,并预防 SQL 注入攻击(所以是系统默认也是我们推荐的语句处理器)
- CallableStatementHandler:存储过程处理器,继承 BaseStatementHandler 抽象类,对应 java.sql.CallableStatement 对象的处理,很明了,它是用来调用存储过程的,增加了存储过程的函数调用以及输出/输入参数的处理支持
- RoutingStatementHandler:路由语句处理器,直接实现了 StatementHandler 接口,作用如其名称,确确实实只是起到了路由功能,并把上面介绍到的三个语句处理器实例作为自身的委托对象而已,所以执行器在构建语句处理器时,都是直接 new 了 RoutingStatementHandler 实例
- RoutingStatementHandler 会根据 sql 的
statementType
选择对应处理的 handler
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());
}
}
}
- 获取到 StatementHandler 之后,就需要执行第 3 步创建 Statement 对象
public class SimpleExecutor extends BaseExecutor {
...
@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();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
...
} finally {
closeStatement(stmt);
}
}
}
- SimpleExecutor 获取 Statement 对象前,会通过 JDBCTransaction 先获取 Connection 对象,即通过 DataSource 返回 Connection 对象。如果开启了日志调试模式,返回的 Connection 对象是经过代理的。然后 RoutingStatementHandler 做预处理得到预编译的 Statement 对象,并参数化后返回 Statement 对象
public class SimpleExecutor extends BaseExecutor {
protected Transaction transaction;
...
protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
...
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
}
- RoutingStatementHandler 再次委派 PreparedStatmentHandler 来处理
public class RoutingStatementHandler implements StatementHandler {
private final StatementHandler delegate;
...
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
return delegate.prepare(connection, transactionTimeout);
}
}
- PreparedStatmentHandler 会通过拿到 BoundSql 中的 sql 之后,通过 Connection 对 sql 进行预编译,得到 PrepareStatement 并返回
public class PreparedStatementHandler extends BaseStatementHandler {
...
protected BoundSql boundSql;
@Override
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
statement = instantiateStatement(connection);
...
return statement;
} catch (SQLException e) {
...
}
}
...
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
...
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareStatement(sql);
} else {
...
}
}
}
- 总结
Statement 参数化设置
- 上面已经阐述到 SimpleExecutor 获取预编译 Statement 对象,下面继续看看参数化的过程,下面会继续交由 RoutingStatementHandler 来 Statement 对象参数化处理
public class SimpleExecutor extends BaseExecutor {
...
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
...
handler.parameterize(stmt);
return stmt;
}
}
- RoutingStatementHandler 委派 PreparedStatementHandler 来执行参数设置,内部调用的是 ParameterHandler 来处理参数化
public class PreparedStatementHandler extends BaseStatementHandler {
protected final ParameterHandler parameterHandler;
...
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
}
- ParameterHandler 参数化处理流程
- 首先从 BoundSql 中,拿到参数化映射列表 ParameterMappings,这个列表是有序的,因为都是从原来的 sql 中按序提取的,然后遍历这个表
- 拿到这个表之后,取到属性名后,进行一系列校验,包括查看 parameterObject 是不是为空,TypeHandlerRegistry 有没有对应参数的处理方法
- 从 ParameterMapping 拿到对应 TypeHandler、JdbcType,然后通过 TypeHandler 来参数化
- 最后把参数化后的 Statement 对象返回到 SimpleExecutor
public class DefaultParameterHandler implements ParameterHandler {
private final TypeHandlerRegistry typeHandlerRegistry;
private final MappedStatement mappedStatement;
private final Object parameterObject;
private final BoundSql boundSql;
private final Configuration configuration;
...
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
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)) {
...
} 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 | SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
}
- 拿到参数化的 Statement 对象后,通过 RoutingStatementHandler 真正执行查询
public class SimpleExecutor extends BaseExecutor {
...
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
...
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
...
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
}
- RoutingStatementHandler 再次委派 PreparedStatementHandler 执行查询。PreparedStatementHandler 拿到 PreparedStatement 后,直接执行查询。然后通过 ResultSetHandler 处理结果集,最后返回查询结果
public class PreparedStatementHandler extends BaseStatementHandler {
protected final ResultSetHandler resultSetHandler;
...
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleResultSets(ps);
}
}
- 总结
解析结果集
- 问题
- 继续回到 PreparedStatementHandler 查询执行,经过执行查询获得结果集之后,需要 ResultSetHandler 对查询结果进行处理
public abstract class BaseStatementHandler implements StatementHandler {
protected final ResultSetHandler resultSetHandler;
...
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.handleResultSets(ps);
}
}
- ResultSetHandler 实际的实现是 DefaultResultSetHandler,处理的流程如下
- 首先对 Statement 获取第一个结果集,并且把结果集包装成 ResultSetWrapper,它会把结果集的 columnNames、classNames、jdbcTypes 属性包装到里面
- 通过 MappedStatement 拿到 Mapper.xml 在 sql 语句中配置的、所有要映射的 ResultMap
- 然后遍历所有的 ResultMap,根据 ResultSetWrapper 映射的所有结果集存放到 multipleResults 局部变量集合中
- 最后返回 multipleResults,如果只有一个结果集,就从 multipleResults 取出第一个
public class DefaultResultSetHandler implements ResultSetHandler {
private final MappedStatement mappedStatement;
private final Configuration configuration;
...
private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
ResultSet rs = stmt.getResultSet();
while (rs == null) {
if (stmt.getMoreResults()) {
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
break;
}
}
}
return rs != null ? new ResultSetWrapper(rs, configuration) : null;
}
@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;
ResultSetWrapper rsw = getFirstResultSet(stmt);
List<ResultMap> resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
validateResultMapsCount(rsw, resultMapCount);
while (rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = resultMaps.get(resultSetCount);
handleResultSet(rsw, resultMap, multipleResults, null);
rsw = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
String[] resultSets = mappedStatement.getResultSets();
if (resultSets != null) {
...
}
return collapseSingleResultList(multipleResults);
}
@SuppressWarnings("unchecked")
private List<Object> collapseSingleResultList(List<Object> multipleResults) {
return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
}
}
- 继续深挖根据映射规则进行结果集,首先通过 ObjectFactory 初始化 DefaultResultHandler,然后对结果集进行映射,转换的结果存入 DefaultResultHandler 中,最后把结果放入 multipleResults
public class DefaultResultSetHandler implements ResultSetHandler {
private final ResultHandler<?> resultHandler;
private final ObjectFactory objectFactory;
private final RowBounds rowBounds;
...
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) {
DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
multipleResults.add(defaultResultHandler.getResultList());
} else {
handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
}
}
} finally {
closeResultSet(rsw.getResultSet());
}
}
}
- 接下来开始对结果集进行映射,首先判断是否有内置嵌套的结果映射,如果不是,则执行简单结果映射
public class DefaultResultSetHandler implements ResultSetHandler {
...
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, parentMapping);
} else {
handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
}
}
}
- 执行简单结果映射,先获取结果集信息,然后根据分页信息只提取部分数据,然后遍历 resultSet 的每一行数据转化成 POJO,再保存映射结果
public class DefaultResultSetHandler implements ResultSetHandler {
...
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
throws SQLException {
DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
ResultSet resultSet = rsw.getResultSet();
skipRows(resultSet, rowBounds);
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
}
}
}
- 执行查询结果封装到 POJO。首先通过 ObjectFactory 创建结果映射的 PO 类对象,然后通过 Configuration 创建 MetaObject 对象,并把 PO 类(即代码里的 rowValue,其实相当于给 PO 多加了点元信息)存到里面去,然后根据 resultMap 结果映射、ResultSetWrapper 封装好的结果集,把值映射到创建到的 PO 类里面去。这三者的关系可以看作 ResultSetWrapper 是 JDBC 对象值,resultMap 是 JDBC 与 Java PO 属性关系映射表,MetaObject 包含元信息的 PO 类对象
public class DefaultResultSetHandler implements ResultSetHandler {
...
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
final ResultLoaderMap lazyLoader = new ResultLoaderMap();
Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final MetaObject metaObject = configuration.newMetaObject(rowValue);
boolean foundValues = this.useConstructorMappings;
if (shouldApplyAutomaticMappings(resultMap, false)) {
foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
}
foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
foundValues = lazyLoader.size() > 0 || foundValues;
rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
}
return rowValue;
}
}
- 创建对象过程其实就是委派给 ObjectFactory 来创建的,也就是上面第 1 步
public class DefaultResultSetHandler implements ResultSetHandler {
...
private final ObjectFactory objectFactory;
...
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
this.useConstructorMappings = false;
final List<Class<?>> constructorArgTypes = new ArrayList<>();
final List<Object> constructorArgs = new ArrayList<>();
Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
for (ResultMapping propertyMapping : propertyMappings) {
if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
break;
}
}
}
this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty();
return resultObject;
}
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
final Class<?> resultType = resultMap.getType();
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
if (hasTypeHandlerForResultObject(rsw, resultType)) {
...
} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
return objectFactory.create(resultType);
} else if (shouldApplyAutomaticMappings(resultMap, false)) {
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
}
...
}
}
- 由于因为这次测试源码的 case 在 Mapper.xml 中定义的 sql 的返回映射属性是 resultType 所以 shouldApplyAutomaticMappings() 返回 true,所以会通过 applyAutomaticMappings 执行 columnName 和 type 属性名映射赋值,存到 rowValue 中
- 首先会通过 createAutomaticMappings() 得到属性映射列表
- 然后遍历这个属性映射列表,通过 TypeHandler 从 ResultSet 拿出属性值
- 最后通过 MetaObject 将属性值设置到 rowValue
public class DefaultResultSetHandler implements ResultSetHandler {
...
private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
boolean foundValues = false;
if (!autoMapping.isEmpty()) {
for (UnMappedColumnAutoMapping mapping : autoMapping) {
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
if (value != null) {
foundValues = true;
}
if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
metaObject.setValue(mapping.property, value);
}
}
}
return foundValues;
}
}
- 得到解析后的结果,返回给 DefaultResultSetHandler 之后,就可以把值映射值拿到,得到最终结果
- 总结
SqlSession 关闭
- 通过 Sqlsession 拿到结果之后,执行完业务流程,就会将 Sqlsession 进行 close()
public class MybatisTest {
@Test
public void test1() throws IOException {
...
sqlSession.close();
}
}
- Sqlsession 关闭,其实就是对 Executor 进行一个关闭清理处理
public class DefaultSqlSession implements SqlSession {
private final Executor executor;
...
@Override
public void close() {
try {
executor.close(isCommitOrRollbackRequired(false));
closeCursors();
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
}
- 然后 CachingExecutor 会对事务管理器进行最后的数据 commit 或者 rollback,然后关闭会话
public class CachingExecutor implements Executor {
private final Executor delegate;
private final TransactionalCacheManager tcm = new TransactionalCacheManager();
...
@Override
public void close(boolean forceRollback) {
try {
if (forceRollback) {
tcm.rollback();
} else {
tcm.commit();
}
} finally {
delegate.close(forceRollback);
}
}
}
完整流程总结