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

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 接口,看看它又干了些啥事。