聊聊Mybatis的Executor之模闆方法模式
模闆方法模式通過模闆方法來指定流程,具體的子類來實作具體的邏輯。
我們看一下Executor接口,它的實作類有BaseExecutor抽象類和CachingExecutor類
BaseExecutor
BaseExecutor抽象類作為模闆方法的抽象模闆類,它把緩存和事務進行實作,具體變化的對資料庫操作的部分由子類去實作
送出事務方法
我們先說說事務管理的commit()方法的實作:
@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();
}
}
- 清除一級緩存
- 調用flushStatements()方法,這個方法中調用doFlushStatements抽象方法,具體操作由子類來實作,主要功能就是清除Statement對象
- 最後送出事務
復原事務的邏輯和這個送出邏輯基本一緻,就不再分析了
Mybatis預設開啟一級緩存,是SqlSession級别的,即通過SqlSession建立會話,如果在這個會話中執行相同的sql,第一次執行的結果會進行緩存,再往後從緩存中查找
緩存資料
我們從它的query()方法來進行分析:
@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);
}
- 先通過createCacheKey()來建立CacheKey對象
- 根據select标簽的 flushCache配置,決定在查詢前是否清空緩存,将其設定為 true 後,隻要語句被調用,都會導緻本地緩存和二級緩存被清空,預設值是false。
- 通過
這段代碼可以看出先通過CacheKey對象來擷取緩存,如果緩存為空的話再調用queryFromDatabase()方法從資料庫中查詢資料,再放入緩存中,下次使用的時候就能從緩存中取list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
- 最後周遊DeferredLoad對象集合處理嵌套查詢,具體的調用
方法deferredLoad.load();
- 根據setting标簽的localCacheScope配置,決定緩存範圍,預設值為 SESSION,會緩存一個會話中執行的所有查詢。 若設定值為 STATEMENT,本地緩存将僅用于執行語句,對相同 SqlSession 的不同查詢将不會進行緩存。
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());