mybatis

mybatis源码分析-selectOne-03

2019-10-08  本文已影响0人  愤怒的奶牛

上篇文章我们分析到了 CachingExecutor ,本文我们就来详细的分析一下 CachingExecutor 。为了方便阅读我们再来看一下 Executor 的类图

Executor.png
1.1 CachingExecutor
public class CachingExecutor implements Executor {

  private final Executor delegate;
  private final TransactionalCacheManager tcm = new TransactionalCacheManager();
// 委派模式 ,持有 具体干活的实现类,自己一定不会干活,
//其实也可以看成是 静态代理的特殊情况,就是代理对象什么也不干,活都让 被代理的对象干了
  public CachingExecutor(Executor delegate) {
    this.delegate = delegate;// delegate -> SimpleExecutor 
    delegate.setExecutorWrapper(this);
  }
....
  @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);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

.....
  @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);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
// 执行 查询的 是 具体的实现了,CachingExecutor 自己不会有操作数据库的逻辑
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
// 执行 查询的 是 具体的实现了,CachingExecutor 自己不会有操作数据库的逻辑
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

上面这段逻辑就是在调用 delegate 对象的 query() 方法,我们先不管 if 条件这些判断,避开对我们看主线代码的影响,都是 走的 下面这句话:

delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);

那么现在所有的关键都在这句话了,通过前面两篇文章的分析,我们知道 delegate -> SimpleExecutor 。接下来我们要看具体的 数据库操作 就要去 SimpleExecutor 了。

1.2 SimpleExecutor

从上面的类图我们知道 SimpleExecutor -> BaseExecutor-> Executor 。
SimpleExecutor 继承了 BaseExecutor ,BaseExecutor 是对接口的抽象实现,这里又有模板设计模式。我们先来看下代码:

/**
 * @author Clinton Begin
 */
public class SimpleExecutor extends BaseExecutor {

  public SimpleExecutor(Configuration configuration, Transaction transaction) {
    super(configuration, transaction);
  }

  @Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

  @Override
  public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = 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);
    }
  }

  @Override
  protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
    Configuration configuration = ms.getConfiguration();
    StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
    Statement stmt = prepareStatement(handler, ms.getStatementLog());
    stmt.closeOnCompletion();
    return handler.queryCursor(stmt);
  }

  @Override
  public List<BatchResult> doFlushStatements(boolean isRollback) {
    return Collections.emptyList();
  }

  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;
  }

}

上面是 SimpleExecutor 对所有方法,我们发现并没有我们 关心的 query() 方法,从类的关系我们也能看出,query 方法应该是在 父类BaseExecutor 中,前面我们说到这里有 模式设计模式,我们就来分析下是怎么回事:先看 BaseExecutor

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

.....
  @Override
  public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  }

  @SuppressWarnings("unchecked")
  @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--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
  }

// 从数据库中查询,这里就是模板方法。
 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;
  }

......
//抽象方法,子类实现
  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;

}
.....

上面省略了部分代码,只保留了关键 部分。doQuery() 是抽象 方法,我们在 SimpleExecutor 中看到了 doQuery() 方法的实现,

@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 负责查询,结果解析封装
 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

上面就 是具体的 doQuery() 方法的实现,从这里我么可以看出 doQuery() 中的 StatementHandler 是完成最后查询和结果封装的接口。到这里我们 分析了 CachingExecutor 和 SimpleExecutor ,源码里面使用了 委派模式和 模板方法,如果你对模板方法有点晕,我们来解释一下,当你在调用 SimpleExecutor 的 query() 方法时,由于子类没有定义该方法,该方法是从父类继承过来的,所以 调用的是父类的query() 方法,而在 父类的query() 方法中 调用的是 抽象的doQuery() 方法,子类实现了 doQuery() 方法,所以doQuery() 方法在 SimpleExecutor.query() 时被回调了,文字解释有点苍白,可以自己写一个demo 就明白了,这也是抽象的很好体现。但是委派模式在这里到底有啥好处,目前我也还不能体会其奥义。后面会接着分析 StatementHandler 接口,看看它又干了些啥事。

上一篇下一篇

猜你喜欢

热点阅读