Mybatis-Executor源码解析

Mybatis3.5.1源码分析

  1. Mybatis-SqlSessionFactoryBuilder,XMLConfigBuilder,XPathParser源码解析
  2. Mybatis-Configuration源码解析
  3. Mybatis-事务对象源码解析
  4. Mybatis-数据源源码解析
  5. Mybatis缓存策略源码解析
  6. Mybatis-DatabaseIdProvider源码解析
  7. Mybatis-TypeHandler源码解析
  8. Mybatis-Reflector源码解析
  9. Mybatis-ObjectFactory,ObjectWrapperFactory源码分析
  10. Mybatis-Mapper各类标签封装类源码解析
  11. Mybatis-XMLMapperBuilder,XMLStatmentBuilder源码分析
  12. Mybatis-MapperAnnotationBuilder源码分析
  13. [Mybatis-MetaObject,MetaClass源码解析]https://www.jianshu.com/p/f51fa552f30a)
  14. Mybatis-LanguageDriver源码解析
  15. Mybatis-SqlSource源码解析
  16. Mybatis-SqlNode源码解析
  17. Mybatis-KeyGenerator源码解析
  18. Mybatis-Executor源码解析
  19. Mybatis-ParameterHandler源码解析
  20. Mybatis-StatementHandler源码解析
  21. Mybatis-DefaultResultSetHandler(一)源码解析
  22. Mybatis-DefaultResultSetHandler(二)源码解析
  23. Mybatis-ResultHandler,Cursor,RowBounds 源码分析
  24. Mybatis-MapperProxy源码解析
  25. Mybatis-SqlSession源码解析
  26. Mybatis-Interceptor源码解析

Executor

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor;

import java.sql.SQLException;
import java.util.List;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;

/**
 * Mybatis的执行器,用于控制ParameterHandler,StatementHandler,ResultSetHandler协调工作
 * 

* 参考博客: *

    *
  1. https://www.cnblogs.com/virgosnail/p/10067964.html
  2. *
  3. https://www.jianshu.com/p/7f6072227390
  4. *
*

* @author Clinton Begin */ public interface Executor { /** * 表示没有结果处理器的标记 */ ResultHandler NO_RESULT_HANDLER = null; /** * update方法,传入MappedStatement 实例和参数,注意这里是不需要RowBounds参数和ResultHandler的 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @return 影响的记录数 */ int update(MappedStatement ms, Object parameter) throws SQLException; /** * 查询,先查缓存,再查数据库 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param resultHandler 结果处理器对象 * @param cacheKey 缓存Key对象 * @param boundSql 参数映射与可执行SQL封装类对象 * @param 返回类型 */ List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException; /** * 查询 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param resultHandler 结果处理器对象 * @param 返回类型 */ List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException; /** * 游标查询 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param 返回类型 */ Cursor queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException; /** * 刷新Statements * @return * @throws SQLException */ List flushStatements() throws SQLException; /** * 事务提交 * @param required */ void commit(boolean required) throws SQLException; /** * 事务回滚 * @param required */ void rollback(boolean required) throws SQLException; /** * 创建缓存的键对象 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameterObject 参数对象 * @param rowBounds Mybatis的分页对象 * @param boundSql 参数映射与可执行SQL封装类对象 */ CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql); /** * 缓存中是否有这个查询的结果 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param key 每次查询操作的特征值抽象而成的类对象 */ boolean isCached(MappedStatement ms, CacheKey key); /** * 清空一级缓存 */ void clearLocalCache(); /** * 延期加载 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param resultObject 结果元对象 * @param property 属性 * @param key 每次查询操作的特征值抽象而成的类对象 * @param targetType 目标类型 */ void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class targetType); /** * 获取事务 * @return 事务对象 */ Transaction getTransaction(); /** * 关闭执行器,回退事务,关闭事务 * @param forceRollback 是否强制回滚 */ void close(boolean forceRollback); /** * 是否已经关闭 */ boolean isClosed(); /** * 设置执行器包装类 * @param executor 执行器 */ void setExecutorWrapper(Executor executor); }

BaseExecutor

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor;

import static org.apache.ibatis.executor.ExecutionPlaceholder.EXECUTION_PLACEHOLDER;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.cache.impl.PerpetualCache;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.statement.StatementUtil;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.logging.jdbc.ConnectionLogger;
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.mapping.StatementType;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * @author Clinton Begin
 */
public abstract class BaseExecutor implements Executor {

  private static final Log log = LogFactory.getLog(BaseExecutor.class);

  /**
   * 事务对象
   */
  protected Transaction transaction;
  /**
   * 执行器包装类
   */
  protected Executor wrapper;

  /**
   * 延期加载队列
   * 

* ConcurrentLinkedQueue: *

    *
  1. 一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。
  2. *
  3. 新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素。
  4. *
*

*/ protected ConcurrentLinkedQueue deferredLoads; /** * 本地缓存,一级缓存 */ protected PerpetualCache localCache; /** * 本地输出参数缓存 */ protected PerpetualCache localOutputParameterCache; /** * mybatis全局配置信息类 */ protected Configuration configuration; protected int queryStack; /** * 执行器是否已经关闭标记 */ private boolean closed; /** * * @param configuration mybatis全局配置信息 * @param transaction 事务 */ protected BaseExecutor(Configuration configuration, Transaction transaction) { //初始化事务 this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<>(); //初始化一个id为LocalCache的缓存对象 this.localCache = new PerpetualCache("LocalCache"); //初始化一个id为LocalOutputParameterCache的缓存对象 this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); //标识自己未关闭 this.closed = false; // 初始化配置对象 this.configuration = configuration; // 包装对象先初始化为自己,另外有一个重写的方法setExecutorWrapper可以重置wrapper对象 this.wrapper = this; } /** * 获取事务,当执行器关闭时抛出异常 * @return {@link #transaction} */ @Override public Transaction getTransaction() { if (closed) { throw new ExecutorException("Executor was closed."); } return transaction; } /** * 关闭执行器,回退事务,关闭事务 * @param forceRollback 是否强制回退事务 */ @Override public void close(boolean forceRollback) { try { try { //回退事务 rollback(forceRollback); } finally { //关闭事务 if (transaction != null) { transaction.close(); } } } catch (SQLException e) { // Ignore. There's nothing that can be done at this point. log.warn("Unexpected exception on closing transaction. Cause: " + e); } finally { //回收数据 transaction = null; deferredLoads = null; localCache = null; localOutputParameterCache = null; closed = true; } } @Override public boolean isClosed() { return closed; } /** * 更新 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @return 影响的记录数 */ @Override public int update(MappedStatement ms, Object parameter) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } clearLocalCache(); return doUpdate(ms, parameter); } /** * 直接调用 {@link BaseExecutor#flushStatements(boolean)} ,参数写死为false,表示不回退事务 */ @Override public List flushStatements() throws SQLException { return flushStatements(false); } /** * 如果不是回退,执行全部保存在执行器中的Statment对象,并将结果封装到BatchResult集合中; * 否则不再执行全部保存在执行器中的Statment对象,直接返回空集合 *

作用于批处理

*

每当调用commit、rollback、close方法时,都会先调用该方法,然后再commit、rollback、close。

* @param isRollBack 是否回退 */ public List flushStatements(boolean isRollBack) throws SQLException { if (closed) { throw new ExecutorException("Executor was closed."); } return doFlushStatements(isRollBack); } /** * 查询,并创建好CacheKey对象 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param resultHandler 结果处理器对象 */ @Override public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { //从MappedStatement对象中根据参数获取BoundSql对象 BoundSql boundSql = ms.getBoundSql(parameter); // 创建缓存Key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); // 调用重载的query方法 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } /** * 查询 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param resultHandler 结果处理器对象 * @param key 缓存对象 * @param boundSql 参数映射与可执行SQL封装类对象 */ @SuppressWarnings("unchecked") @Override public List 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."); } //如果配置了flushCacheRequired为true,则会在执行器执行之前就清空本地一级缓存,换句话说就是关闭一级缓存功能 if (queryStack == 0 && ms.isFlushCacheRequired()) { //查询堆栈为0且需要清空缓存,则执行清空缓存 clearLocalCache(); } List list; try { //查询堆栈 + 1 queryStack++; //如果此次查询的resultHandler为null(默认为null),则尝试从本地缓存中获取已经缓存的的结果,否则为null list = resultHandler == null ? (List) localCache.getObject(key) : null; //判断是否有已缓存的结果 if (list != null) { //如果查到localCache缓存,处理localOutputParameterCache handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { //没有缓存结果,则从数据库查询结果 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { // 查询堆栈数 -1 queryStack--; } if (queryStack == 0) { //从延迟加载集合做,遍历加载数据到list中 for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; } @Override public Cursor queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException { //将参数传入boundSql BoundSql boundSql = ms.getBoundSql(parameter); return doQueryCursor(ms, parameter, rowBounds, boundSql); } @Override public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class targetType) { if (closed) { throw new ExecutorException("Executor was closed."); } DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration, targetType); //如果能加载则立即加载,否则加入到延迟加载队列中 if (deferredLoad.canLoad()) { deferredLoad.load(); } else { //添加到延迟加载队列中,这里重新new一个DeferredLoad对象没理解为啥。 deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType)); } } @Override public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) { if (closed) { throw new ExecutorException("Executor was closed."); } CacheKey cacheKey = new CacheKey(); // MappedStatement的id cacheKey.update(ms.getId()); // 分页参数的offset cacheKey.update(rowBounds.getOffset()); // 分页参数的limit cacheKey.update(rowBounds.getLimit()); // SQL语句本身 cacheKey.update(boundSql.getSql()); // 传递给jdbc的参数 List parameterMappings = boundSql.getParameterMappings(); //类型处理注册器 TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // mimic DefaultParameterHandler logic for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty();//获取对应映射名 if (boundSql.hasAdditionalParameter(propertyName)) { //获取propertyName的额外映射值 value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { //如果参数对象为null,value即为null value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { //如果存在parameterObject对应类型处理器,value即为parameterObject value = parameterObject; } else { //从元对象中获取propertyName的值 MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); } } if (configuration.getEnvironment() != null) { // issue #176 //获取环境Id,因为有可能配置了多个环境,所以要加上环境Id做标识 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; } /** * 是否已经缓存 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param key 每次查询操作的特征值抽象而成的类对象 */ @Override public boolean isCached(MappedStatement ms, CacheKey key) { //如果从本地缓存集合中获取key对应的对象不为null return localCache.getObject(key) != null; } /** * 提交前,清空一级缓存和刷新Statements * @param required 如果为true,提交事务 */ @Override public void commit(boolean required) throws SQLException { if (closed) { throw new ExecutorException("Cannot commit, transaction is already closed"); } //清空一级缓存 clearLocalCache(); //刷新Statements flushStatements(); if (required) { transaction.commit(); } } /** * 回退前,清空一级缓存和刷新Statements * @param required 如果为true,回退事务 */ @Override public void rollback(boolean required) throws SQLException { if (!closed) { try { //清空一级缓存 clearLocalCache(); //刷新Statements,并回退 flushStatements(true); } finally { if (required) { transaction.rollback(); } } } } /** * 清空一级缓存,只有在执行器关闭以后才会有效果 */ @Override public void clearLocalCache() { if (!closed) { //清除本地缓存 localCache.clear(); //清除输出参数缓存 localOutputParameterCache.clear(); } } /** * 执行[insert][update][delete]SQL,并返回更新记录数 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @return 更新记录数 */ protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException; /** * 如果不是回退,执行全部保存在执行器中的Statment对象,并将结果封装到BatchResult集合中; * 否则不再执行全部保存在执行器中的Statment对象,直接返回空集合 *

作用于批处理

*

每当调用commit、rollback、close方法时,都会先调用该方法,然后再commit、rollback、close。

* @param isRollback 是否回退 */ protected abstract List doFlushStatements(boolean isRollback) throws SQLException; /** * 执行查询SQL,返回结果对象集合 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param resultHandler 结果处理器对象 * @param boundSql 参数映射与可执行SQL封装类对象 */ protected abstract List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException; /** * 执行查询SQL,返回游标对象 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param boundSql 参数映射与可执行SQL封装类对象,已将参数对象加入到boundSql中 */ protected abstract Cursor doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException; /** * 关闭Statement,捕捉了关闭Statement的SQLException但不进行处理 * @param statement 执行 SQL 语句并返回它所生成结果的对象 */ protected void closeStatement(Statement statement) { //如果statemenet不为null if (statement != null) { try { //关闭statement statement.close(); } catch (SQLException e) { // ignore 忽略关闭statement的SQLException } } } /** * Apply a transaction timeout. 应用事务超时。事务超时大于查询时间,则不做更改;否则将查询时间修改成事务时间 * @param statement a current statement 当前的Statmet * @throws SQLException if a database access error occurs, this method is called on a closed Statement * @since 3.4.0 * @see StatementUtil#applyTransactionTimeout(Statement, Integer, Integer) */ protected void applyTransactionTimeout(Statement statement) throws SQLException { StatementUtil.applyTransactionTimeout(statement, statement.getQueryTimeout(), transaction.getTimeout()); } /** * 将本地缓存输出参数对象赋值到paramter中 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param key 缓存对象 * @param parameter 参数对象 * @param boundSql 参数映射与可执行SQL封装类对象 */ private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) { if (ms.getStatementType() == StatementType.CALLABLE) { //获取缓存参数对象 final Object cachedParameter = localOutputParameterCache.getObject(key); if (cachedParameter != null && parameter != null) { //缓存参数对象的元对象 final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter); //参数对象的元对象 final MetaObject metaParameter = configuration.newMetaObject(parameter); for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) { if (parameterMapping.getMode() != ParameterMode.IN) { final String parameterName = parameterMapping.getProperty(); //从缓存参数元对象中获取parameterName的值,并通过metaParamter赋值到parameter final Object cachedValue = metaCachedParameter.getValue(parameterName); metaParameter.setValue(parameterName, cachedValue); } } } } } /** * 从数据库中查找出来 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param resultHandler 结果处理器对象 * @param key 缓存Key对象 * @param boundSql 参数映射与可执行SQL封装类对象 * @param 返回类型 */ private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List 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 localOutputParameterCache.putObject(key, parameter); } return list; } /** * 获取数据库连接 * @param statementLog stat * @return * @throws SQLException */ protected Connection getConnection(Log statementLog) throws SQLException { Connection connection = transaction.getConnection(); if (statementLog.isDebugEnabled()) { //开启了Dugger模式,会新建Connection代理对象 return ConnectionLogger.newInstance(connection, statementLog, queryStack); } else { return connection; } } @Override public void setExecutorWrapper(Executor wrapper) { this.wrapper = wrapper; } /** * 延迟加载类 */ private static class DeferredLoad { /** * 结果对象 */ private final MetaObject resultObject; /** * 属性名 */ private final String property; /** * 目标类型 */ private final Class targetType; /** * 缓存Key */ private final CacheKey key; /** * 本地缓存 */ private final PerpetualCache localCache; /** * 对象工厂,从mybatis全局配置信息中获取 */ private final ObjectFactory objectFactory; /** * 结果提取器 */ private final ResultExtractor resultExtractor; // issue #781 /** * * @param resultObject 结果对象 * @param property 属性名 * @param key 缓存Key * @param localCache 本地缓存 * @param configuration mybatis全局配置新 * @param targetType 目标类型 */ public DeferredLoad(MetaObject resultObject, String property, CacheKey key, PerpetualCache localCache, Configuration configuration, Class targetType) { this.resultObject = resultObject; this.property = property; this.key = key; this.localCache = localCache; this.objectFactory = configuration.getObjectFactory(); this.resultExtractor = new ResultExtractor(configuration, objectFactory); this.targetType = targetType; } /** * 是否可以加载 *

* 从 {@link #localCache} 中获取 {@link #key} 不为null且获取出来的值不是 {@link ExecutionPlaceholder#EXECUTION_PLACEHOLDER} (占位符) 就认为是可加载的。 *

* @return true为可加载,否则为false */ public boolean canLoad() { return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER; } /** * 从 {@link #localCache} 中获取 {@link #key} 的记录数据,并根据 {@link #targetType} * 将记录数据加入到targetType的对象,并将targetType对象加入resultObject,键名 * 为 {@link #property} */ public void load() { @SuppressWarnings("unchecked") // we suppose we get back a List List list = (List) localCache.getObject(key); Object value = resultExtractor.extractObjectFromList(list, targetType); resultObject.setValue(property, value); } } }

SimpleExecutor

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
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;

/**
 * 简单执行器
 * @author Clinton Begin
 */
public class SimpleExecutor extends BaseExecutor {

  /**
   *
   * @param configuration mybatis全局配置信息
   * @param transaction 事务对象
   */
  public SimpleExecutor(Configuration configuration, Transaction transaction) {
    super(configuration, transaction);
  }

  /**
   * 执行[insert][update][delete]SQL,并返回更新记录数
   * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameter 参数对象
   * @return 更新的记录数
   */
  @Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      //获取mybatis全局配置信息
      Configuration configuration = ms.getConfiguration();
      //构建一个RoutingStatementHandler对象
      /**
       * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,
       * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
       */
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      //构建Statement对象,并将参数值传入Statement对象中
      stmt = prepareStatement(handler, ms.getStatementLog());
      //通知stmt将[insert,update,delete]推送到数据库,并返回更新记录数
      return handler.update(stmt);
    } finally {
      // 关闭Statement,捕捉了关闭Statement的SQLException但不进行处理
      closeStatement(stmt);
    }
  }

  /**
   * 执行查询SQL,返回结果对象集合
   * @param ms  Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameter 参数对象
   * @param rowBounds Mybatis的分页对象
   * @param resultHandler 结果处理器对象
   * @param boundSql 参数映射与可执行SQL封装类对象
   * @param  结果对象
   * @return 结果对象集合
   */
  @Override
  public  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      //获取mybatis全局配置信息
      Configuration configuration = ms.getConfiguration();
      //构建一个RoutingStatementHandler对象
      /**
       * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,
       * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
       */
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      //构建Statement对象,并将参数值传入Statement对象中
      stmt = prepareStatement(handler, ms.getStatementLog());
      //通知Statement将[select]推送到数据库并返回对应查询结果
      return handler.query(stmt, resultHandler);
    } finally {
      // 关闭Statement,捕捉了关闭Statement的SQLException但不进行处理
      closeStatement(stmt);
    }
  }

  /**
   * 执行查询SQL,返回游标对象
   * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameter 参数对象
   * @param rowBounds Mybatis的分页对象
   * @param boundSql 参数映射与可执行SQL封装类对象,已将参数对象加入到boundSql中
   * @param  结果对象类型
   * @return 存放结果对象的游标
   */
  @Override
  protected  Cursor doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
    //获取mybatis全局配置信息
    Configuration configuration = ms.getConfiguration();
    //构建一个RoutingStatementHandler对象
    /**
     * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,
     * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
     */
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
    //构建Statement对象,并将参数值传入Statement对象中
    Statement stmt = prepareStatement(handler, ms.getStatementLog());
    //若Statement执行了该方法,则当所有依赖于该Statement的ResultSet关闭时,该Statement会自动关闭。
    stmt.closeOnCompletion();
    //通知stmt将[select]推送到数据库并返回对应游标结果
    return handler.queryCursor(stmt);
  }

  /**
   * 如果不是回退,执行全部保存在执行器中的Statment对象,并将结果封装到BatchResult集合中;
   * 否则不再执行全部保存在执行器中的Statment对象,直接返回空集合
   * 

作用于批处理

*

每当调用commit、rollback、close方法时,都会先调用该方法,然后再commit、rollback、close。

* @param isRollback 是否回退 */ @Override public List doFlushStatements(boolean isRollback) { /** * SimpleExecutor没有缓存Statement对象,每执行一次update或select,就开启一个Statement对象, * 用完立刻关闭Statement对象。根据对应的sql直接执行即可,不会做一些额外的操作。 */ //返回空集合 return Collections.emptyList(); } /** * 构建Statement对象,并将参数值传入Statement对象中 * @param handler Statement处理器 * @param statementLog MappedStatement对象的日志属性对象 * @return Statement对象 */ private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; //获取数据库连接 Connection connection = getConnection(statementLog); //根据MappedStatement对象配置的StatementType,去创建Statement对象或则PreparedStatment或则CallableStatment stmt = handler.prepare(connection, transaction.getTimeout()); //将参数值插入stmt handler.parameterize(stmt); return stmt; } }

BatchExecutor

/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor;

import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
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;

/**
 * 批量执行器
 * @author Jeff Butler
 */
public class BatchExecutor extends BaseExecutor {

  /**
   * 批量更新返回值,表示最大批量执行条数
   */
  public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;

  /**
   * Statement对象集合
   */
  private final List statementList = new ArrayList<>();
  /**
   * 批处理结果对象集合
   */
  private final List batchResultList = new ArrayList<>();
  /**
   * 当前可执行SQL
   */
  private String currentSql;
  /**
   * 当前 Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   */
  private MappedStatement currentStatement;

  /**
   *
   * @param configuration mybatis全局配置信息
   * @param transaction 事务对象
   */
  public BatchExecutor(Configuration configuration, Transaction transaction) {
    super(configuration, transaction);
  }

  /**
   * 执行[insert][update][delete]SQL,并返回更新记录数
   * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameterObject 参数对象
   * @return 更新记录数
   */
  @Override
  public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
    //mybatis全局配置信息
    final Configuration configuration = ms.getConfiguration();
    //构建一个RoutingStatementHandler对象
    /**
     * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,
     * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
     */
    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
    //获取参数映射与可执行SQL封装类对象
    final BoundSql boundSql = handler.getBoundSql();
    //获取可执行SQL
    final String sql = boundSql.getSql();
    final Statement stmt;
    //如果sql等于当前sql 且 ms等于当前DML标签封装类对象
    if (sql.equals(currentSql) && ms.equals(currentStatement)) {
      //获取Statement对象集合的最后一个Statement对象位置
      int last = statementList.size() - 1;
      //获取Statement对象集合的最后一个Statement对象
      stmt = statementList.get(last);
      //设置stmt的事务超时时间
      applyTransactionTimeout(stmt);
      //将参数值传入stmt
      handler.parameterize(stmt);//fix Issues 322
      //获取批量结果对象集合最后一个批量结果对象
      BatchResult batchResult = batchResultList.get(last);
      //将参数对象添加到批量结果对象中
      batchResult.addParameterObject(parameterObject);
      //如果sql不等于当前sql 或者 ms不等于当前DML标签封装类对象
    } else {
      //获取数据库连接对象
      Connection connection = getConnection(ms.getStatementLog());
      //构建Statement对象,并设置事务超时时长
      stmt = handler.prepare(connection, transaction.getTimeout());
      //将参数值传入stmt
      handler.parameterize(stmt);    //fix Issues 322
      //设置当前sql为sql
      currentSql = sql;
      //设置当前DML标签封装类对象为ms
      currentStatement = ms;
      //添加stmt到Statement对象集合
      statementList.add(stmt);
      /**
       * BatchResult:批处理结果,简单的POJO对象,
       */
      //构建BatchResult对象并添加到batchResult集合中
      batchResultList.add(new BatchResult(ms, sql, parameterObject));
    }
    // 将 {@code statement} 添加到批处理队列
    handler.batch(stmt);
    //写死返回最大批量执行条数
    return BATCH_UPDATE_RETURN_VALUE;
  }

  /**
   * 执行查询SQL,返回结果对象集合
   * @param ms  Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameterObject 参数对象
   * @param rowBounds Mybatis的分页对象
   * @param resultHandler 结果处理器对象
   * @param boundSql 参数映射与可执行SQL封装类对象
   * @param  结果对象类型
   * @return 结果对象集合
   */
  @Override
  public  List doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException {
    Statement stmt = null;
    try {
      //执行全部保存在执行器中的Statment对象,不回退事务,并将结果封装到BatchResult集合中
      flushStatements();
      //获取mybatis全局配置信息
      Configuration configuration = ms.getConfiguration();
      //构建一个RoutingStatementHandler对象
      /**
       * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,
       * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
       */
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
      //获取数据库连接
      Connection connection = getConnection(ms.getStatementLog());
      //构建Statement对象,并设置statement对象的查询超时时间
      stmt = handler.prepare(connection, transaction.getTimeout());
      //将参数值赋值到stmt里
      handler.parameterize(stmt);
      //通知stmt将[select]推送到数据库并返回对应查询结果
      return handler.query(stmt, resultHandler);
    } finally {
      //关闭Statement,捕捉了关闭Statement的SQLException但不进行处理
      closeStatement(stmt);
    }
  }

  /**
   * 执行查询SQL,返回游标对象
   * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
   * @param parameter 参数对象
   * @param rowBounds Mybatis的分页对象
   * @param boundSql 参数映射与可执行SQL封装类对象,已将参数对象加入到boundSql中
   * @param  结果对象类型
   * @return 结果对象游标
   */
  @Override
  protected  Cursor doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
    //执行全部保存在执行器中的Statment对象,不回退事务,并将结果封装到BatchResult集合中
    flushStatements();
    //获取mybatis全局配置信息
    Configuration configuration = ms.getConfiguration();
    //构建一个RoutingStatementHandler对象
    /**
     * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型,
     * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象
     */
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
    //获取数据库连接
    Connection connection = getConnection(ms.getStatementLog());
    //构建Statement对象,并设置statement对象的查询超时时间
    Statement stmt = handler.prepare(connection, transaction.getTimeout());
    //当stmt执行完后关闭
    stmt.closeOnCompletion();
    //将参数值赋值到stmt里
    handler.parameterize(stmt);
    //通知Statement将[select]推送到数据库并返回对应游标结果
    return handler.queryCursor(stmt);
  }

  /**
   * 如果不是回退,执行全部保存在执行器中的Statment对象,并将结果封装到BatchResult集合中;
   * 否则不再执行全部保存在执行器中的Statment对象,直接返回空集合
   * 

作用于批处理

*

每当调用commit、rollback、close方法时,都会先调用该方法,然后再commit、rollback、close。

* @param isRollback 是否回退 * @return 批处理结果对象集合 */ @Override public List doFlushStatements(boolean isRollback) throws SQLException { try { //创建批量结果对象集合 List results = new ArrayList<>(); //如果是回退 if (isRollback) { //不再执行执行全部保存在执行器中的Statment对象,直接返回空集合 return Collections.emptyList(); } //下面代码只有提交时才会执行 //遍历statement对象集合 for (int i = 0, n = statementList.size(); i < n; i++) { //获取Statement对象 Statement stmt = statementList.get(i); //应用事务超时。事务超时大于查询时间,则不做更改;否则将查询时间修改成事务时间 applyTransactionTimeout(stmt); //获取批处理结果 BatchResult batchResult = batchResultList.get(i); try { /** * executeBatch:将一批SQL脚本提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组 */ //执行SQL,将每个SQL执行完的更新记录数所组成的数组赋值到batchResult batchResult.setUpdateCounts(stmt.executeBatch()); //获取DML标签封装对象 MappedStatement ms = batchResult.getMappedStatement(); //获取参数对象集合 List parameterObjects = batchResult.getParameterObjects(); //获取Key生成器 KeyGenerator keyGenerator = ms.getKeyGenerator(); //如果Key生成器是Jdbc3KeyGenerator.class if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) { //将keyGenerator强转为Jdbc3KeyGenerator对象 Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator; //将 stmt 返回的主键赋值到 parameterObjects jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects); //如果Key生成器不是NoKeyGenerator类 } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141 //变量参数对象集合 for (Object parameter : parameterObjects) { //通知Key生成,执行执行完stmt后的业务逻辑 keyGenerator.processAfter(this, ms, stmt, parameter); } } // Close statement to close cursor #1109 关闭语句关闭游标; //关闭statement closeStatement(stmt); } catch (BatchUpdateException e) { //拼装异常信息描述,描述是第几个statement对象执行是抛出异常,告诉用户因为执行不成功,将会被回退 StringBuilder message = new StringBuilder(); message.append(batchResult.getMappedStatement().getId()) .append(" (batch index #") .append(i + 1) .append(")") .append(" failed."); if (i > 0) { message.append(" ") .append(i) .append(" prior sub executor(s) completed successfully, but will be rolled back."); } throw new BatchExecutorException(message.toString(), e, results, batchResult); } //将batchResult对象添加批量结果对象集合 results.add(batchResult); } return results; } finally { //遍历Statement对象 for (Statement stmt : statementList) { //关闭Statement对象 closeStatement(stmt); } //将当前SQL置为null currentSql = null; //清空statement集合 statementList.clear(); //清空批处理结果对象集合 batchResultList.clear(); } } }

ReuseExecutor

/**
 *    Copyright 2009-2018 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
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;

/**
 * 

* 作用于重复使用执行,其定义了一个Map,将执行的sql作为key, * 将执行的Statement作为value保存,这样执行相同的sql时就可以使用已经存在的Statement,就不需要新创建了 *

*

* 在执行commit,rollback,close,flushStatements方法时,才会对这个缓存Map进行遍历元素逐一关闭, * 然后清空缓存Map里的元素 *

* @author Clinton Begin */ public class ReuseExecutor extends BaseExecutor { /** * 存储SQL与Statement对象关系映射的映射集合,这里直接简称为statement映射集合 */ private final Map statementMap = new HashMap<>(); /** * * @param configuration mybatis全局配置信息 * @param transaction 事务对象 */ public ReuseExecutor(Configuration configuration, Transaction transaction) { super(configuration, transaction); } /** * 执行[insert][update][delete]SQL,并返回更新记录数 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @return 更新记录数 */ @Override public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { //获取全局配置信息 Configuration configuration = ms.getConfiguration(); //构建一个RoutingStatementHandler对象 /** * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型, * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象 */ StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); //构建Statement对象,并将参数值传入Statement对象中 Statement stmt = prepareStatement(handler, ms.getStatementLog()); //通知stmt将[insert,update,delete]推送到数据库,并返回更新记录数 return handler.update(stmt); //并没有关闭stmt } /** * * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param resultHandler 结果处理器对象 * @param boundSql 参数映射与可执行SQL封装类对象 * @param 结果对象类型 * @return 结果对象集合 */ @Override public List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { //获取mybatis全局配置信息 Configuration configuration = ms.getConfiguration(); //构建一个RoutingStatementHandler对象 /** * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型, * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象 */ StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); //构建Statement对象,并将参数值传入Statement对象中 Statement stmt = prepareStatement(handler, ms.getStatementLog()); //通知Statement将[select]推送到数据库并返回对应查询结果 return handler.query(stmt, resultHandler); //并没有关闭statement } /** * 执行查询SQL,返回游标对象 * @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类 * @param parameter 参数对象 * @param rowBounds Mybatis的分页对象 * @param boundSql 参数映射与可执行SQL封装类对象,已将参数对象加入到boundSql中 * @param 结果对象类型 * @return 存放结果对象的游标 */ @Override protected Cursor doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException { //获取mybatis全局配置信息 Configuration configuration = ms.getConfiguration(); //构建一个RoutingStatementHandler对象 /** * RountingStatementHandler:一个具体实现类,这个类中并没有对Statement对象具体使用,还是根据得到Excutor类型, * 决定创建何种类型StatementHandler对象。在MyBatis工作时,使用的StatementHandler接口对象实际上就是RoutingStatementHandler对象 */ StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql); //构建Statement对象,并将参数值传入Statement对象中 Statement stmt = prepareStatement(handler, ms.getStatementLog()); //通知stmt将[select]推送到数据库并返回对应游标结果 return handler.queryCursor(stmt); //并没有关闭stmt } /** * 如果不是回退,执行全部保存在执行器中的Statment对象,并将结果封装到BatchResult集合中; * 否则不再执行全部保存在执行器中的Statment对象,直接返回空集合 *

作用于批处理

*

每当调用commit、rollback、close方法时,都会先调用该方法,然后再commit、rollback、close。

* @param isRollback 是否回退 * @return 空集合,mybatis */ @Override public List doFlushStatements(boolean isRollback) { //遍历Statement映射集合 for (Statement stmt : statementMap.values()) { //关闭statement对象 closeStatement(stmt); } //清空Statement映射结合 statementMap.clear(); //返回空集合,ResueExecutor并没有做批处理,要想有批处理效果,请应用BatchExecutor return Collections.emptyList(); } /** * 构建Statement对象,并将参数值传入Statement对象中 * @param handler Statement处理器 * @param statementLog MappedStatement对象的日志属性对象 * @return Statement对象 */ private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; //获取参数映射与可执行SQL封装类对象 BoundSql boundSql = handler.getBoundSql(); //获取可执行SQL String sql = boundSql.getSql(); //如果 sql 存在Statement映射集合中,而且 sql 对应的Statement对象没有关闭 if (hasStatementFor(sql)) { // 从statement映射集合中获取sql 对应的Statement对象 stmt = getStatement(sql); ///应用事务超时。事务超时大于查询时间,则不做更改;否则将查询时间修改成事务时间 applyTransactionTimeout(stmt); } else { //获取数据库连接对象 Connection connection = getConnection(statementLog); //构建Statement对象,并设置事务超时时长 stmt = handler.prepare(connection, transaction.getTimeout()); //将 sql 和 stmt 加入到Statement映射集合中 putStatement(sql, stmt); } //将参数值传入stmt handler.parameterize(stmt); return stmt; } /** * 判断{@code sql} 是否存在Statement映射集合中,而且 {@code sql} 对应的Statement对象是否没有关闭 * @param sql 可执行SQL脚本 * @return 如果从statement映射集合的键名集里存在sql,而且sql对应的Statement对象并没有关闭,返回true;否则,返回flase */ private boolean hasStatementFor(String sql) { try { //如果从statement映射集合的键名集里存在sql,而且sql对应的Statement对象并没有关闭,返回true;否则,返回flase return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed(); } catch (SQLException e) { //抛出SQLException时返回false return false; } } /** * 从statement映射集合中获取 {@code s} 对应的Statement对象 * @param s 可执行SQL字符串,statement映射集合的键 * @return {@code s} 对应的Statement对象 */ private Statement getStatement(String s) { return statementMap.get(s); } /** * 将 {@code sql} 和 {@code stmt} 加入到Statement映射集合中 * @param sql 可执行SQL脚本字符串 * @param stmt 执行 {@code sql} 的Statement对象 */ private void putStatement(String sql, Statement stmt) { statementMap.put(sql, stmt); } }

你可能感兴趣的:(Mybatis-Executor源码解析)