1. 程式人生 > 實用技巧 >Mybatis深入淺出之快取機制

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