Mybatis深入淺出之快取機制
一、簡述
MyBatis是常見的Java資料庫訪問層框架之一。MyBatis為提高其資料庫查詢效能,提供了快取機制(查詢快取),包括一級快取和二級快取。由於專案的業務場景多樣化以及分散式構架系統的普及,Mybatis快取造成一些髒資料場景也是偶有發生,本文結合Mybatis原始碼以及官網等相關資料,幫助更多的開發人員熟悉掌握Mybatis快取機制。
二、一級快取
Mybatis在一次Sqlsession資料庫查詢之後,會將查詢結果以鍵值對形式儲存到記憶體中,當前Sqlsession後續以相同sql查詢時,會直接去查詢記憶體快取,避免資料庫查詢,提高查詢效能。
應用場景:當前執行緒同一個SqlSession會話中執行多次相同sql查詢。
1、流程圖:
2、 時序圖:
3、一級快取特點
- 作用粒度:同一個SqlSession物件sql查詢。
- 預設設定:Mybatis預設開啟一級快取。
- 作用:同一Sqlsession物件執行多次相同sql查詢,避免資料庫訪問,提高查詢效能,節省資料庫訪問開銷。
- 清理方式:增刪查改commit()都清理一級快取(包括查詢commit)
- 關閉方式:配置中localCacheScope設定為:STATEMENT。 即:<setting name="localCacheScope" value="STATEMENT"/> ,預設數值:SESSION,即開啟一級快取。
4、實驗
-
一級快取命中
1>.測試demo
2>.配置
3>.執行結果
第一次查詢進行資料庫連線查詢,第二次第三次查詢為命中快取查詢。
-
清理一級快取
執行結果:第一次查詢之後,進行了commit操作,會清理一級快取。因此第二次查詢時仍然需要連線資料庫,傳送查詢sql至資料庫執行sql查詢。
-
關閉一級快取
執行結果:關閉一級快取,同一SqlSession多次sql查詢不共享快取,每次都需要傳送sql至資料庫查詢。
三、二級快取
一級快取其共享範圍就是一個SqlSession內部,如果多個SqlSession之間需要共享快取,則需要使用到二級快取,其共享範圍為Namespace。開啟二級快取後,會使用CachingExecutor裝飾Executor,進入一級快取的查詢流程前,先在CachingExecutor進行二級快取的查詢。
適用場景:多執行緒執行相同namespace下查詢語句,直接查詢二級快取,避免資料庫連線查詢,提高效能。
1、流程圖
- 二級快取開啟後,同一個namespace下的所有操作語句,都影響著同一個Cache,即二級快取可以被多個SqlSession共享,可以視為一個全域性的變數。
- 二級快取依賴於一級快取,因此關閉一級快取,即使二級快取開啟也沒有資料。
- 執行順序:二級快取 -> 一級快取 -> 資料庫。
2、開啟二級快取
- 步驟一:配置setting,即:<setting name="cacheEnabled" value="true"/>
- 步驟二:指定namespace配置開啟,即:<cache/>
3、二級快取開啟實驗
執行結果:sqlSession2查詢命中二級快取。命中率為:1/2=0.5。
注意:
1、二級快取依賴於一級快取寫入,不關閉sqlSession1,不會寫入當前namespace的二級快取,造成二級快取失效。
2、Mybatis二級快取物件儲存在硬碟中,因此需要namespace下實體物件序列化,如果不序列話執行會報錯:
Exception in thread "main" org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: ****。 解決方案:實體實現序列化介面public class TruckInfo implements Serializable {}
序列化:將資料從記憶體儲存到硬碟。(注意:類的屬性為例項或者有父類都需要序列化,即為級聯序列化,避免資料部分丟失)
反序列化:將資料從硬碟儲存到記憶體。
4、二級快取特點
- Mybatis預設關閉二級快取。
- 作用粒度:相同namespace下所有sql語句共享快取,即:支援不同sqlSession共享快取。
- 資料寫入時機:sqlSession.close(),即:sql會話關閉後,統一將當前namespace下的一級快取寫入二級快取。節約I/O,提高I/O效能。
- 二級快取清理:與清理一級快取相同,執行commit()方法,但是僅僅針對增刪改commit,查詢commit無法觸發清理。
- 關閉單個查詢語句二級快取方式:xml sql語句設定關閉useCache="false"。
1>.二級快取清理:
2>.關閉單個sql查詢二級快取
關閉了二級快取查詢,即使儲存了快取也不起作用。
5、二級快取特殊場景
- 多個sql.xml檔案中namespace相同,則這些xml產生的Mapper物件仍然共享同一個namespace二級快取。
- 兩張表TA,其namespaceA、TB其namespaceB,A表的部分sqlA不規範編寫到namespaceB中,則該部分sqlA的二級快取儲存在namespaceB中,當使用namespaceA二級快取時可能造成髒資料,因為部分更新快取儲存在namespaceB中。解決方案:將namespaceA引用關聯到namespaceB中,保證兩個對映檔案對應的SQL操作都使用的是同一塊快取了。 快取的粒度變粗了,多個Mapper namespace下的所有sql操作都會對快取使用造成影響。
- 應對分散式部署專案,一個應用多個例項機器造成髒資料,解決方案:<1>禁用二級快取,<2>使用分散式快取中介軟體。
6、二級快取中介軟體
當前有不少第三方二級快取中介軟體,比如:memcache、ehcache等,根據Mybatis規範要求,整合第三方二級快取中介軟體,必須實現org.apache.ibatis.cache介面。
快取中介軟體的一個優點在於:可以設定二級快取為記憶體快取,減少了I/O消耗,提高了查詢效能。
四、Mybatis快取比對
對比項 | 一級快取 | 二級快取 |
作用粒度 | sqlSession | nameSpace |
開啟方式 | 預設開啟 | 配置開啟 |
儲存方式 | 記憶體 | 硬碟 |
清理時機 | 增刪改查commit() | 增刪改commit() |
儲存時機 | 執行完sql | sqlSession.close() |
關閉方式 | 設定statement模式 |
不啟用->全域性關閉 設定useCache="false"->單個sql查詢關閉 |
髒資料場景 | 多執行緒併發場景,不同執行緒不同sqlSession更新資料 |
分散式多例項機器部署 namespace不規範編寫其他表sql |