mybatis源碼分析-selectOne-03

上篇文章我們分析到了 CachingExecutor ,本文我們就來詳細的分析一下 CachingExecutor 。為了方便閱讀我們再來看一下 Executor 的類圖

Executor.png
1.1 CachingExecutor
public class CachingExecutor implements Executor {

  private final Executor delegate;
  private final TransactionalCacheManager tcm = new TransactionalCacheManager();
// 委派模式 ,持有 具體干活的實現(xiàn)類,自己一定不會干活,
//其實也可以看成是 靜態(tài)代理的特殊情況,就是代理對象什么也不干,活都讓 被代理的對象干了
  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) {
// 執(zhí)行 查詢的 是 具體的實現(xiàn)了,CachingExecutor 自己不會有操作數(shù)據(jù)庫的邏輯
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
// 執(zhí)行 查詢的 是 具體的實現(xiàn)了,CachingExecutor 自己不會有操作數(shù)據(jù)庫的邏輯
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

上面這段邏輯就是在調(diào)用 delegate 對象的 query() 方法,我們先不管 if 條件這些判斷,避開對我們看主線代碼的影響,都是 走的 下面這句話:

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

那么現(xiàn)在所有的關(guān)鍵都在這句話了,通過前面兩篇文章的分析,我們知道 delegate -> SimpleExecutor 。接下來我們要看具體的 數(shù)據(jù)庫操作 就要去 SimpleExecutor 了。

1.2 SimpleExecutor

從上面的類圖我們知道 SimpleExecutor -> BaseExecutor-> Executor 。
SimpleExecutor 繼承了 BaseExecutor ,BaseExecutor 是對接口的抽象實現(xiàn),這里又有模板設(shè)計模式。我們先來看下代碼:

/**
 * @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 對所有方法,我們發(fā)現(xiàn)并沒有我們 關(guān)心的 query() 方法,從類的關(guān)系我們也能看出,query 方法應(yīng)該是在 父類BaseExecutor 中,前面我們說到這里有 模式設(shè)計模式,我們就來分析下是怎么回事:先看 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;
  }

// 從數(shù)據(jù)庫中查詢,這里就是模板方法。
 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 {
// 具體的 查詢 任務(wù)交給 子類去做,自己只定義 查詢的步驟
      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;
  }

......
//抽象方法,子類實現(xiàn)
  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;

}
.....

上面省略了部分代碼,只保留了關(guān)鍵 部分。doQuery() 是抽象 方法,我們在 SimpleExecutor 中看到了 doQuery() 方法的實現(xiàn),

@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 負責(zé)查詢,結(jié)果解析封裝
 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.query(stmt, resultHandler);
    } finally {
      closeStatement(stmt);
    }
  }

上面就 是具體的 doQuery() 方法的實現(xiàn),從這里我么可以看出 doQuery() 中的 StatementHandler 是完成最后查詢和結(jié)果封裝的接口。到這里我們 分析了 CachingExecutor 和 SimpleExecutor ,源碼里面使用了 委派模式和 模板方法,如果你對模板方法有點暈,我們來解釋一下,當(dāng)你在調(diào)用 SimpleExecutor 的 query() 方法時,由于子類沒有定義該方法,該方法是從父類繼承過來的,所以 調(diào)用的是父類的query() 方法,而在 父類的query() 方法中 調(diào)用的是 抽象的doQuery() 方法,子類實現(xiàn)了 doQuery() 方法,所以doQuery() 方法在 SimpleExecutor.query() 時被回調(diào)了,文字解釋有點蒼白,可以自己寫一個demo 就明白了,這也是抽象的很好體現(xiàn)。但是委派模式在這里到底有啥好處,目前我也還不能體會其奧義。后面會接著分析 StatementHandler 接口,看看它又干了些啥事。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容