當前位置:
首頁 > 知識 > 隨筆-64 文章-0 評論-26

隨筆-64 文章-0 評論-26


根據前文Mybatis源碼分析-SqlSessionTemplate的簡單分析,對於SqlSession的CURD操作都需要經過Executor介面的update/query方法,本文將分析下BaseExecutor如何解析執行sql語句

BaseExecutor-抽象類

其是Executor介面的實現類但為抽象類,另外一個則為具體實現類為CachingExecutor,主要是通過對象適配的設計模式在原來的executor上再附上緩存的屬性,有興趣的可自行查閱。先從構造函數看一發

protected BaseExecutor(Configuration configuration, Transaction transaction) {
//事務對象
this.transaction = transaction;
this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>;
this.localCache = new PerpetualCache("LocalCache");
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
//表明exector的狀態
this.closed = false;
//主文件屬性,主要獲取MappedStatement對象
this.configuration = configuration;
this.wrapper = this;
}

BaseExecutor#update-SqlSession之insert/update/delete入口

具體源碼如下

@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance.resource(ms.getResource).activity("executing an update").object(ms.getId);
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache;
//供子類複寫執行CUD操作
return doUpdate(ms, parameter);
}

BaseExecutor#query-SqlSession之select入口

具體源碼如下

@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//獲取綁定的sql,並將參數對象與sql語句的#{}一一對應
BoundSql boundSql = ms.getBoundSql(parameter);
//獲取cacheKey供緩存,包含完整的語句、參數等
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
//比原先多傳入CacheKey和BoundSql參數
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

具體的查詢處理邏輯如下

@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) {
//此處嘗試對Callable類型的表達式進行處理,主要是針對mode=out類型的參數
//此參數主要是通過map來定義,直接從map中獲取
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//從資料庫中獲取並進行緩存處理,其也會調用子類需複寫的doQuery方法
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;
}

由上可知,BaseExecutor對CRUD操作均轉化為對子類的doUpdate/doQuery方法的調用,並一般都會相應的結果進行緩存以免頻繁請求資料庫導致性能下降。本文則從SimpleExecutor子類來進行分析

SimpleExecutor

分別看下SimpleExecutor複寫的doUpdate和doQuery方法,具體源碼如下 doUpdate

@Override
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Configuration configuration = ms.getConfiguration;
//創建StatementHandler來處理update
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//創建表達式對象Statement
Statement stmt = prepareStatement(handler, ms.getStatementLog);
return handler.update(stmt);
}

doQuery

@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Configuration configuration = ms.getConfiguration;
//創建StatementHandler來處理query
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//創建表達式對象Statement
Statement stmt = prepareStatement(handler, ms.getStatementLog);
return handler.<E>query(stmt, resultHandler);
}

doUpdate/doQuery代碼的執行邏輯一致,均是先創建StatementHandler對象,然後通過prepareStatement方法創建表達式對象,供前者調用處理update/query方法

SimpleExecutor#prepareStatement-創建預表達式對象

邏輯如下

//handler對象對應的為RoutingStatementHandler對象,其實也是個適配管理類
//可根據MappedStatement的statementType來確定表達式處理handler類,後續講解
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
//獲取連接對象,如果該日誌等級為debug,則會列印相應的處理日誌,採用代理實現
Connection connection = getConnection(statementLog);
//創建真實的Statement對象,比如SimpleStatement/PrepareStatement/CallableStatement
stmt = handler.prepare(connection, transaction.getTimeout);
//設置返回參數
handler.parameterize(stmt);
return stmt;
}

小結

  1. BaseExecutor抽象類提供了對CRUD操作的入口,並帶有緩存效應,子類只需要複寫doUpdate和doQuery抽象方法即可

  2. SimpleExecutor-簡單的處理實現類,即基本每次對相同的sql語句都會創建新的Statement對象;ReuseExecutor-復用處理實現類,即對相同的sql語句會緩存Statement對象;BatchExecutor-批處理實現類

  3. 最終獲取Statement對象以及執行sql語句的解釋權在於StatementHandler介面,詳情看下節內容

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

mysql中varchar和char區別
Oracle PL/SQL 的記錄型變數
SpringMVC 和 MyBatis 支持 Jackson 的經驗談
Mastering KVM Virtualization>:第二章 KVM內部原理

TAG:科技優家 |

您可能感興趣

No.670 | 1986年的一篇《人民日報》評論員文章
0709-0715運勢 | 只說事實,不下評論
印太策略-西太與北約新的縫合點:東方時事評論|2018-02-28
2018年本田CR-V評論,規格和介紹
大歐羅巴計劃掩護下的西方資本複雜轉進:東方時事評論|2018-03-02
信心爆棚!華碩驍龍835 Win10電腦公布價格:5443元 網友評論醉了
12星座2018年8月26日運勢詳解,網友紛紛評論太准了
《經濟評論》2018年第4期
《外交評論》2018年第4期
300元稿酬|每日好詩《岡仁波齊》徵集評論(7.31截止)
中東看上去仍很熱鬧:東方時事評論|2018-02-09
50篇學術訪談實錄:一份557頁的年終答卷 | AI科技評論2017年度特輯第二彈
《外交評論》2018年第2期
《普林斯頓評論》2018美國最佳回報學院Top50!
2018年梅賽德斯-賓士E400 Cabriolet評論
疑似小米7配置曝光 16MP雙攝/4480mAh |網友神評論
羅永浩宣布堅果pro2「特別版」1899元,網友9個字評論!
神評論|女生身高160,體重106斤,算胖嗎?網友:高160,體重103
《紅豆》2018.04:同期評論我讀《天蟲》:泅渡與重生
看美專家評論中俄五代機:蘇-57不算五代機,殲-20比蘇-57還差!