Mybatis源码:Executor 模板模式
by yan 20220301
模板模式
在模板模式(Template Pattern)中,一個抽象類公開定義了執(zhí)行它的方法的方式/模板。它的子類可以按需要重寫方法實現(xiàn),但調(diào)用將以抽象類中定義的方式進行。這種類型的設(shè)計模式屬于行為型模式。
意圖:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
主要解決:一些方法通用,卻在每一個子類都重新寫了這一方法。
何時使用:有一些通用的方法。
如何解決:將這些通用算法抽象出來。
關(guān)鍵代碼:在抽象類實現(xiàn),其他步驟在子類實現(xiàn)。
應(yīng)用實例: 1、在造房子的時候,地基、走線、水管都一樣,只有在建筑的后期才有加壁櫥加?xùn)艡诘炔町悺?2、西游記里面菩薩定好的 81 難,這就是一個頂層的邏輯骨架。 3、spring 中對 Hibernate 的支持,將一些已經(jīng)定好的方法封裝起來,比如開啟事務(wù)、獲取 Session、關(guān)閉 Session 等,程序員不重復(fù)寫那些已經(jīng)規(guī)范好的代碼,直接丟一個實體就可以保存。
優(yōu)點: 1、封裝不變部分,擴展可變部分。 2、提取公共代碼,便于維護。 3、行為由父類控制,子類實現(xiàn)。
缺點:每一個不同的實現(xiàn)都需要一個子類來實現(xiàn),導(dǎo)致類的個數(shù)增加,使得系統(tǒng)更加龐大。
使用場景: 1、有多個子類共有的方法,且邏輯相同。 2、重要的、復(fù)雜的方法,可以考慮作為模板方法。
注意事項:為防止惡意操作,一般模板方法都加上 final 關(guān)鍵詞。
創(chuàng)建Executor
在openSqlSession中創(chuàng)建Executor
Mybatis insert
時序圖: insert 過程
Mybatis Executor 相關(guān)類圖
BaseExecutor :實現(xiàn)了Executor的全部方法,包括對緩存,事務(wù),連接提供了一系列的模板方法, 這些模板方法中留出來了四個抽象的方法等待子類去實現(xiàn)如下
protected abstract int doUpdate(MappedStatement ms, Object parameter)throws SQLException;protected abstract List<BatchResult> doFlushStatements(boolean isRollback)throws SQLException;protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)throws SQLException;protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)throws SQLException; //模板方法@Overridepublic 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();return doUpdate(ms, parameter);}@Overridepublic <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")@Overridepublic <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 #601deferredLoads.clear();if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}return list;}@Overridepublic <E> Cursor<E> queryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);return doQueryCursor(ms, parameter, rowBounds, boundSql);}SimpleExecutor: 特點是每次執(zhí)行完畢后都會將創(chuàng)建出來的statement關(guān)閉掉,他也是默認(rèn)的執(zhí)行器類型
ReuseExecutor: 在它在本地維護了一個容器,用來存放針對每條sql創(chuàng)建出來的statement,下次執(zhí)行相同的sql時,會先檢查容器中是否存在相同的sql,如果存在就使用現(xiàn)成的,不再重復(fù)獲取
BatchExecutor: 特點是進行批量修改,她會將修改操作記錄在本地,等待程序觸發(fā)提交事務(wù),或者是觸發(fā)下一次查詢時,批量執(zhí)行修改
BaseExecutor與一級緩存
BaseExecutor維護的一級緩存。
一級緩存是sqlsession級的:
sqlsession->excutor->localcache
什么是這個一級緩存呢? **一級緩存就是上面代碼中的localCache。
一級緩存叫l(wèi)ocalCache,它的封裝類叫PerpetualCache。
perpetual意味永不間斷,一級緩存默認(rèn)存在,也關(guān)不了。
但是在與Spring整合時,Spring把這個緩存給關(guān)了,這并不奇怪,因為spring 直接干掉了這個sqlSession。
一級緩存什么時候被填充的值呢?填充值的操作在一個叫做queryFromDataBase()的方法里面。
清空一級緩存的方法就是BaseExecutor的update()模板方法里。
CachingExecutor與二級緩存
二級緩存是共享級,在configuration里的。在mapper builder 加載配置 build時創(chuàng)建的。
//Configuration.javaprotected final Map<String, Cache> caches = new StrictMap<>("Caches collection");CachingExecutor通過TransactionalCacheManager可能獲取二級緩存里的數(shù)據(jù)。
二級緩存中存放的不是對象,而是被序列化后存儲的數(shù)據(jù),需要反序列化出來。
參考
:
https://
www.runoob.com/design-pattern/template-pattern.html
https://www.cnblogs.com/ZhuChangwu/p/11745562.html
總結(jié)
以上是生活随笔為你收集整理的Mybatis源码:Executor 模板模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一起学微软Power BI系列-使用技巧
- 下一篇: MySQL基础