MyBatis源码简读——2.3 2 Executor执行器

Executor

**
 * 执行器接口
 * @author Clinton Begin
 */
public interface Executor {

  // 空的handler对象的枚举
  ResultHandler NO_RESULT_HANDLER = null;

  // 更新 or 插入 or 删除,由传入的 MappedStatement 的 SQL 所决定
  int update(MappedStatement ms, Object parameter) throws SQLException;

  // 查询,带 ResultHandler + CacheKey + BoundSql
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey cacheKey, BoundSql boundSql) throws SQLException;

  // 查询,带 ResultHandler
  <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;

  // 查询,返回值为 Cursor
  <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException;

  // 刷入批处理语句
  List<BatchResult> flushStatements() throws SQLException;

  // 提交事务
  void commit(boolean required) throws SQLException;

  // 回滚事务
  void rollback(boolean required) throws SQLException;

  // 创建 CacheKey 对象
  CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql);

  // 判断是否缓存
  boolean isCached(MappedStatement ms, CacheKey key);

  // 清除本地缓存
  void clearLocalCache();

  // 延迟加载
  void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key, Class<?> targetType);

  // 获得事务
  Transaction getTransaction();

  // 关闭事务
  void close(boolean forceRollback);

  // 判断事务是否关闭
  boolean isClosed();

  // 设置包装的 Executor 对象
  void setExecutorWrapper(Executor executor);

}

执行器的顶级接口,所有的数据操作最终使用这里的方法

其类的实现关系
在这里插入图片描述
下面我们来看看相关实现类的逻辑

BaseExecutor

是一个抽象类实现了Executor一些基础方法,其主要的数据操作方法,留给子类实现

  // 更新和查询操作没有实现,由子类实现
  protected abstract int doUpdate(MappedStatement ms, Object parameter)
      throws SQLException;

  protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
      throws SQLException;

  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;

  protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
      throws SQLException;

主要实现了事务和缓存相关的逻辑

 // 提交
  @Override
  public void commit(boolean required) throws SQLException {
    if (closed) {
      throw new ExecutorException("Cannot commit, transaction is already closed");
    }
    // 清空本地缓存
    clearLocalCache();
    // 刷入批处理语句
    flushStatements();
    // 是否要求提交事务,如果是,则提交事务
    if (required) {
      transaction.commit();
    }
  }

  // 回滚
  @Override
  public void rollback(boolean required) throws SQLException {
    if (!closed) {
      try {
        // 清空本地缓存
        clearLocalCache();
        // 刷入批处理数据
        flushStatements(true);
      } finally {
        if (required) {
          // 假如需要回滚事务,进行回滚
          transaction.rollback();
        }
      }
    }
  }
  ....

缓存

  @Override
  public void clearLocalCache() {
    // 清理一级(本地)缓存
    if (!closed) {
      // 清理本地缓存,和参数缓存
      localCache.clear();
      localOutputParameterCache.clear();
    }
  }
  ....

SimpleExecutor

执行器的简单实现

doQuery

执行查询

// 类似其他的doUpdate
  @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());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
  
   // 初始化 StatementHandler 对象
  private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    // 获得连接
    Connection connection = getConnection(statementLog);
    // 创建Statement
    stmt = handler.prepare(connection, transaction.getTimeout());
    // 设置 SQL 上的参数,例如 PrepareStatement 对象上的占位符
    handler.parameterize(stmt);
    return stmt;
  }

将mybatis对SQL的对象参数,封装成java的Statement进行数据操作

doQueryCursor

类似于doQuery只不过调用方法从

return handler.query(stmt, resultHandler); 

修改为

return handler.queryCursor(stmt);

doUpdate

 @Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      // 获得配置
      Configuration configuration = ms.getConfiguration();
      // 创建StatementHandler
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      // 执行StatementHandler
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      // 关闭StatementHandler
      closeStatement(stmt);
    }
  }

类似doQuery,其实里面逻辑无法是从select方法缓存update方法

doFlushStatements

// 不存在批量操作的情况,所以直接返回空数组
  @Override
  public List<BatchResult> doFlushStatements(boolean isRollback) {
    return Collections.emptyList();
  }

ReuseExecutor

可重用的 Executor 实现类,每次开始读或写操作,优先从缓存中获取对应的 Statement 对象。如果不存在,才进行创建。执行完成后,不关闭该 Statement 对象

其主要逻辑和SimpleExecutor区别不大,以doQuery为例子

 @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
    Statement stmt = prepareStatement(handler, ms.getStatementLog());
    return handler.query(stmt, resultHandler);
  }
  
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    BoundSql boundSql = handler.getBoundSql();
    String sql = boundSql.getSql();
    // 判断是否存在对应的 Statement 对象
    // 存在 从缓存中获得 Statement 或 PrepareStatement 对象
    if (hasStatementFor(sql)) {
      stmt = getStatement(sql);
      // 设置事务超时时间
      applyTransactionTimeout(stmt);
      // 不存在
    } else {
      // 获得 Connection 对象
      Connection connection = getConnection(statementLog);
      // 创建 Statement 或 PrepareStatement 对象
      stmt = handler.prepare(connection, transaction.getTimeout());
      // 添加到缓存中
      putStatement(sql, stmt);
    }
    // 设置 SQL 上的参数,例如 PrepareStatement 对象上的占位符
    handler.parameterize(stmt);
    return stmt;
  }
  
    private Statement getStatement(String s) {
    return statementMap.get(s);
  }

可以看到,他会先从缓存中获得PrepareStatement,假如不存在就会创建一个新的,
而在SimpleExecutor在执行完操作之后我们看到一句代码

closeStatement(stmt);

而ReuseExecutor是不存在的,ReuseExecutor执行完操作后不关闭Statement

doFlushStatements

 @Override
  public List<BatchResult> doFlushStatements(boolean isRollback) {
    // 关闭缓存的 Statement 对象
    for (Statement stmt : statementMap.values()) {
      closeStatement(stmt);
    }
    statementMap.clear();
    // 返回空集合
    return Collections.emptyList();
  }

执行批量Statements关闭操作

BatchExecutor

继承 BaseExecutor 抽象类,批量执行的 Executor 实现类

doQuery

  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException {
    Statement stmt = null;
    try {
      // 输入批处理
      flushStatements();
      // 配置,Statement处理,获得连接,Statement,然后设置参数,执行操作
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection, transaction.getTimeout());
      handler.parameterize(stmt);
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

其批处理的方法在flushStatements中

flushStatements

请过几次嵌套最终实现批处理的代码逻辑是

// org/apache/ibatis/executor/BatchExecutor.java
 @Override
  public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
    try {
      // 批处理
      List<BatchResult> results = new ArrayList<>();
      // 如果回滚,设置空
      if (isRollback) {
        return Collections.emptyList();
      }
      // 遍历 statementList 和 batchResultList 数组,逐个提交批处理
      for (int i = 0, n = statementList.size(); i < n; i++) {
        // 获得 Statement 和 BatchResult 对象
        Statement stmt = statementList.get(i);
        applyTransactionTimeout(stmt);
        BatchResult batchResult = batchResultList.get(i);
        try {
          // 批量执行
          batchResult.setUpdateCounts(stmt.executeBatch());
          // 处理主键生成
          MappedStatement ms = batchResult.getMappedStatement();
          List<Object> parameterObjects = batchResult.getParameterObjects();
          KeyGenerator keyGenerator = ms.getKeyGenerator();
          if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
            Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
            jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
          } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
            for (Object parameter : parameterObjects) {
              keyGenerator.processAfter(this, ms, stmt, parameter);
            }
          }
          // Close statement to close cursor #1109
          // 关闭 Statement 对象
          closeStatement(stmt);
        } catch (BatchUpdateException e) {
          // 如果发生异常,则抛出 BatchExecutorException 异常
          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);
        }
        // 添加到结果集
        results.add(batchResult);
      }
      return results;
    } finally {
      // 关闭 Statement 们
      for (Statement stmt : statementList) {
        closeStatement(stmt);
      }
      // 置空 currentSql、statementList、batchResultList 属性
      currentSql = null;
      statementList.clear();
      batchResultList.clear();
    }
  }

整体的逻辑

  • 首先取出statementList 和 batchResultList 数组中的数据
  • 然后依次提交批处理
  • 处理完成后再循环statementList依次关闭对应的statement,然后清空statementList,batchResultList
  • 然后上一层方法获得本次连接Connection connection = getConnection(ms.getStatementLog())
  • 拿到执行的statement中进行执行并获得结果进行处理

二级缓存

CachingExecutor

支持二级缓存的 Executor 的实现类

  // 事务缓存管理器
  private final TransactionalCacheManager tcm = new TransactionalCacheManager();

其内部维持一个事务缓存管理器

query
 @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    // 获得缓存
    Cache cache = ms.getCache();
    // 缓存存在则执行里面逻辑,不存则是直接调用委托执行器 delegate 的对应的方法
    if (cache != null) {
      // 如果需要清空缓存,则进行清空
      flushCacheIfRequired(ms);
      // 当 MappedStatement#isUseCache() 方法,返回 true 时,才使用二级缓存
      if (ms.isUseCache() && resultHandler == null) {
        // 暂时忽略,存储过程相关
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
                // 缓存中获取结果
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          // 不存在则是直接调用委托执行器 delegate 的对应的方法
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }
  • 其内部在执行操作的时候,会优先从缓存中取出数据。
直接调用委托方法
 // 执行器
  private final Executor delegate;
  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;
    delegate.setExecutorWrapper(this);
  }

其内部维持一个Executor 对象,其他执行器接口的方法的实现,全部使用构造时候传入的执行器进行具体的实现。

TransactionalCacheManager

支持事务的缓存管理器,因为二级缓存是支持跨 Session 进行共享,此处需要考虑事务,那么,必然需要做到事务提交时,才将当前事务中查询时产生的缓存,同步到二级缓存中。这个功能,就通过 TransactionalCacheManager 来实现

public class TransactionalCacheManager {

  // Cache 和 TransactionalCache 的映射
  private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<>();

  // 清空
  public void clear(Cache cache) {
    getTransactionalCache(cache).clear();
  }

  // 取值
  public Object getObject(Cache cache, CacheKey key) {
    return getTransactionalCache(cache).getObject(key);
  }

  // 存放
  public void putObject(Cache cache, CacheKey key, Object value) {
    getTransactionalCache(cache).putObject(key, value);
  }

  // 提交,循环值获得事务,执行提交
  public void commit() {
    for (TransactionalCache txCache : transactionalCaches.values()) {
      txCache.commit();
    }
  }

  // 回滚,循环值获得事务,执行回滚
  public void rollback() {
    for (TransactionalCache txCache : transactionalCaches.values()) {
      txCache.rollback();
    }
  }

  private TransactionalCache getTransactionalCache(Cache cache) {
    return transactionalCaches.computeIfAbsent(cache, TransactionalCache::new);
  }

}

其内部位置一个缓存的映射,key为Cache,value为TransactionalCache 。代码不算太麻烦,里面除了获取数据,也有提交和回滚的逻辑。

TransactionalCache

public class TransactionalCache implements Cache {

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

  // 委托给cache,二级缓存
  private final Cache delegate;
  // 提交时,清空
  private boolean clearOnCommit;
  // 等待提交内容
  private final Map<Object, Object> entriesToAddOnCommit;
  // 查找不到的key集合
  private final Set<Object> entriesMissedInCache;

  public TransactionalCache(Cache delegate) {
    this.delegate = delegate;
    this.clearOnCommit = false;
    this.entriesToAddOnCommit = new HashMap<>();
    this.entriesMissedInCache = new HashSet<>();
  }

  @Override
  public String getId() {
    return delegate.getId();
  }

  @Override
  public int getSize() {
    return delegate.getSize();
  }

  @Override
  public Object getObject(Object key) {
    // issue #116
    // 从缓存中查询结果,假如找不到将key保存到entriesMissedInCache
    Object object = delegate.getObject(key);
    if (object == null) {
      entriesMissedInCache.add(key);
    }
    // issue #146
    // 如果 clearOnCommit 为 true ,表示处于持续清空状态,则返回 null
    if (clearOnCommit) {
      return null;
    } else {
      return object;
    }
  }

  @Override
  public ReadWriteLock getReadWriteLock() {
    return null;
  }

  @Override
  public void putObject(Object key, Object object) {
    // 暂存 KV 到 entriesToAddOnCommit 中
    entriesToAddOnCommit.put(key, object);
  }

  @Override
  public Object removeObject(Object key) {
    return null;
  }

  @Override
  public void clear() {
    // 标记 clearOnCommit 为 true
    clearOnCommit = true;
    entriesToAddOnCommit.clear();
  }

  public void commit() {
    // 如果 clearOnCommit 为 true ,则清空 delegate 缓存
    if (clearOnCommit) {
      delegate.clear();
    }
    // 将 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate 中
    flushPendingEntries();
    // 重置
    reset();
  }

  public void rollback() {
    // 从 delegate 移除出 entriesMissedInCach
    unlockMissedEntries();
    reset();
  }

  // 重置缓存配置
  private void reset() {
    clearOnCommit = false;
    entriesToAddOnCommit.clear();
    entriesMissedInCache.clear();
  }

  private void flushPendingEntries() {
    // 将 entriesToAddOnCommit 刷入 delegate 中
    for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
      delegate.putObject(entry.getKey(), entry.getValue());
    }
    // 将 entriesMissedInCache 刷入 delegate 中
    for (Object entry : entriesMissedInCache) {
      if (!entriesToAddOnCommit.containsKey(entry)) {
        delegate.putObject(entry, null);
      }
    }
  }

  private void unlockMissedEntries() {
    for (Object entry : entriesMissedInCache) {
      try {
        delegate.removeObject(entry);
      } catch (Exception e) {
        log.warn("Unexpected exception while notifiying a rollback to the cache adapter."
            + "Consider upgrading your cache adapter to the latest version.  Cause: " + e);
      }
    }
  }

}

实现 Cache 接口,支持事务的 Cache 实现类,主要用于二级缓存中

可以看到针对缓存的最终操作是委托给 private final Cache delegate; java缓存实现类来进行的。

getObject
  @Override
  public Object getObject(Object key) {
    // issue #116
    // 从缓存中查询结果,假如找不到将key保存到entriesMissedInCache
    Object object = delegate.getObject(key);
    if (object == null) {
      entriesMissedInCache.add(key);
    }
    // issue #146
    // 如果 clearOnCommit 为 true ,表示处于持续清空状态,则返回 null
    if (clearOnCommit) {
      return null;
    } else {
      return object;
    }
  }

当无法获取的缓存的key会被保存在entriesMissedInCache中做个记录

putObject
  @Override
  public void putObject(Object key, Object object) {
    // 暂存 KV 到 entriesToAddOnCommit 中
    entriesToAddOnCommit.put(key, object);
  }

数据并不会第一时间被保存在缓存中delegate,而是保存在entriesToAddOnCommit,中等待提交后才刷入缓存中

commit
  public void commit() {
    // 如果 clearOnCommit 为 true ,则清空 delegate 缓存
    if (clearOnCommit) {
      delegate.clear();
    }
    // 将 entriesToAddOnCommit、entriesMissedInCache 刷入 delegate 中
    flushPendingEntries();
    // 重置
    reset();
  }
  private void flushPendingEntries() {
    // 将 entriesToAddOnCommit 刷入 delegate 中
    for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
      delegate.putObject(entry.getKey(), entry.getValue());
    }
    // 将 entriesMissedInCache 刷入 delegate 中
    for (Object entry : entriesMissedInCache) {
      if (!entriesToAddOnCommit.containsKey(entry)) {
        delegate.putObject(entry, null);
      }
    }
  }

当提交的时候才会将数据整体刷入缓存中

创建 Executor 对象

缓存的创建在Configuration里面

// org/apache/ibatis/session/Configuration.java
  // 新建执行器的方法入口
  public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
  }
// 新建执行器
  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    // 创建执行器类别
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    // 获取对应的执行器
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    // 如果开启缓存,创建 CachingExecutor 对象,进行包装
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    // 应用插件
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }
public enum ExecutorType {
  // SimpleExecutorc
  SIMPLE,
  // ReuseExecutor
  REUSE,
  // BatchExecutor
  BATCH
}

总结

最后可以看到,执行器的多种实现类中,大多数只是对其他执行器的扩展最终执行业务的逻辑在SimpleExecutor中,而根据SimpleExecutor的逻辑中最终所有的操作是StatementHandler对java的Statement进行操作的逻辑。那么下一篇我们就看看StatementHandler的详细逻辑。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大·风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值