读mybatis源码之七:执行器Exceutor之四大执行器

一、SimpleExecutor

SimpleExecutor继承BaseExecutor
主要实现:doUpdate、doQuery、doFlushStatements
可以看代码主要是:
1、获取声明处理类:StatementHandler handler
2、获取声明类:stmt = prepareStatement(handler, ms.getStatementLog());
3、处理声明,执行SQL处理

二、ReuseExecutor

与SimpleExecutor不同的是:重用声明
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    BoundSql boundSql = handler.getBoundSql();
    String sql = boundSql.getSql();
    if (hasStatementFor(sql)) {
      stmt = getStatement(sql);
    } else {
      Connection connection = getConnection(statementLog);
      stmt = handler.prepare(connection);
      putStatement(sql, stmt);
    }
    handler.parameterize(stmt);
    return stmt;
  }
SQL语句一样的,就用同样的声明。不过这个好像也仅仅是同一个session内的有效。

三、BatchExecutor

先看update
 public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
    final Configuration configuration = ms.getConfiguration();
    final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
    final BoundSql boundSql = handler.getBoundSql();
    final String sql = boundSql.getSql();
    final Statement stmt;
    if (sql.equals(currentSql) && ms.equals(currentStatement)) {
      int last = statementList.size() - 1;
      stmt = statementList.get(last);
      BatchResult batchResult = batchResultList.get(last);
      batchResult.addParameterObject(parameterObject);
    } else {
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection);
      currentSql = sql;
      currentStatement = ms;
      statementList.add(stmt);
      batchResultList.add(new BatchResult(ms, sql, parameterObject));
    }
    handler.parameterize(stmt);
    handler.batch(stmt);
    return BATCH_UPDATE_RETURN_VALUE;
  }
if (sql.equals(currentSql) && ms.equals(currentStatement))
表明同一个SQL语句使用同一个申明,应用场景很简单,就是我们的批量删除和批量插入,在没有参数的SQL语句他们就是一样的,不一样的只是参数而已。具体参数处理在StatementHandler里面去设置的。也是同一个session内的批量操作。是不是很奇怪没有提交?看完查询再说:
public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException {
    Statement stmt = null;
    try {
      flushStatements();
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, rowBounds, resultHandler, boundSql);
      Connection connection = getConnection(ms.getStatementLog());
      stmt = handler.prepare(connection);
      handler.parameterize(stmt);
      return handler.<E>query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }
重点flushStatements,为什么这里会做这件事呢?因为在同一session里面如果又是批量操作,又是查询的话,那么就必须保证批量操作数据提交上去了。也就是为什么有这个,这个方法主要的事情归结到doFlushStatements,就是批量更新提交。查询有提交,批量更新那个怎么没有提交?在sqlsession里面commit调用BaseExecutor里面commit
public void commit(boolean required) throws SQLException {
    if (closed) throw new ExecutorException("Cannot commit, transaction is already closed");
    clearLocalCache();
    flushStatements();
    if (required) {
      transaction.commit();
    }
  }
flushStatements();
注意使用批量的时候,如果不开启批量模式,是没有使用批量更新的,使用sessionFactory.openSession(ExecutorType.BATCH, false);
网上大部分例子都没有正确使用批量更新,因为mybatis默认是SimpleExecutor执行器

四、CachingExecutor

缓存执行器,顾名思义跟缓存有关系,这里的缓存是全局缓存,configuration里面的cacheEnabled参数决定,默认为true
也就是默认是开启全局缓存,但是只是这里开启就可以吗?详细看看CachingExecutor这个类:
先看创建这个类:
  public CachingExecutor(Executor delegate) {
    this(delegate, false);
  }
  public CachingExecutor(Executor delegate, boolean autoCommit) {
    this.delegate = delegate;
    this.autoCommit = autoCommit;
  }
装饰模式,也就是说缓存执行器,增强了其他的执行器,不同的是他先执行缓存处理。(以后需要加缓存时可以借鉴)
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
  }
更新先flush缓存
 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, parameterObject, boundSql);
        if (!dirty) {
          cache.getReadWriteLock().readLock().lock();
          try {
            @SuppressWarnings("unchecked")
            List<E> cachedList = (List<E>) cache.getObject(key);
            if (cachedList != null) return cachedList;
          } finally {
            cache.getReadWriteLock().readLock().unlock();
          }
        }
        List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
        tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
        return list;
      }
    }
    return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

查询重点:
Cache cache = ms.getCache();  看mapper上配置缓存没有,如果有执行缓存逻辑,所以默认全局缓存开启后,每个mapper上必须配置是否使用缓存,缓存才有效。这个缓存在MappedStatement上,所以是全局的,非仅仅在session内有效。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章