mybatis緩存機制和第三方緩存集成

緩存是一般的ORM 框架都會提供的功能,目的就是提升查詢的效率和減少數據庫的壓力。跟Hibernate 一樣,MyBatis 也有一級緩存和二級緩存,並且預留了集成第三方緩存的接口.
根據緩存的作用域分爲一級緩存和二級緩存

一級緩存(本地緩存)

一級緩存也叫本地緩存,MyBatis 的一級緩存是在會話(SqlSession)層面進行緩存的。MyBatis 的一級緩存是默認開啓的,不需要任何的配置。首先我們必須去弄清楚一個問題,在MyBatis 執行的流程裏面,涉及到這麼多的對象,那麼緩存PerpetualCache 應該放在哪個對象裏面去維護?如果要在同一個會話裏面共享一級緩存,這個對象肯定是在SqlSession 裏面創建的,作爲SqlSession 的一個屬性。

DefaultSqlSession 裏面只有兩個屬性,Configuration 是全局的,所以緩存只可能放在Executor 裏面維護——SimpleExecutor/ReuseExecutor/BatchExecutor 的父類BaseExecutor 的構造函數中持有了PerpetualCache。在同一個會話裏面,多次執行相同的SQL 語句,會直接從內存取到緩存的結果,不會再發送SQL 到數據庫。但是不同的會話裏面,即使執行的SQL 一模一樣(通過一個Mapper 的同一個方法的相同參數調用),也不能使用到一級緩存。

每當我們使用MyBatis開啓一次和數據庫的會話,MyBatis會創建出一個SqlSession對象表示一次數據庫會話。

在對數據庫的一次會話中,我們有可能會反覆地執行完全相同的查詢語句,如果不採取一些措施的話,每一次查詢都會查詢一次數據庫,而我們在極短的時間內做了完全相同的查詢,那麼它們的結果極有可能完全相同,由於查詢一次數據庫的代價很大,這有可能造成很大的資源浪費。

爲了解決這一問題,減少資源的浪費,MyBatis會在表示會話的SqlSession對象中建立一個簡單的緩存,將每次查詢到的結果結果緩存起來,當下次查詢的時候,如果判斷先前有個完全一樣的查詢,會直接從緩存中直接將結果取出,返回給用戶,不需要再進行一次數據庫查詢了。

如下圖所示,MyBatis會在一次會話的表示----一個SqlSession對象中創建一個本地緩存(local cache),對於每一次查詢,都會嘗試根據查詢的條件去本地緩存中查找是否在緩存中,如果在緩存中,就直接從緩存中取出,然後返回給用戶;否則,從數據庫讀取數據,將查詢結果存入緩存並返回給用戶
緩存並不陌生大家,根據不同的情況使用不同的緩存策略,一說緩存我們
在這裏插入圖片描述
一級緩存的生命週期有多長?

  • MyBatis在開啓一個數據庫會話時,會 創建一個新的SqlSession對象,SqlSession對象中會有一個新的Executor對象,Executor對象中持有一個新的PerpetualCache對象;當會話結束時,SqlSession對象及其內部的Executor對象還有PerpetualCache對象也一併釋放掉。
  • 如果SqlSession調用了close()方法,會釋放掉一級緩存PerpetualCache對象,一級緩存將不可用;
  • 如果SqlSession調用了clearCache(),會清空PerpetualCache對象中的數據,但是該對象仍可使用;
  • SqlSession中執行了任何一個update操作(update()、delete()、insert()) ,都會清空PerpetualCache對象的數據,但是該對象可以繼續使用;
    注意: close clearCache方法區別在於sqlsession是否可以使用,比如我們需要一級緩存失效就可以使用clearCache()方法到達我們的目的

在這裏插入圖片描述
BaseExcutor中的query中便說明了一級緩存中有數據直接從一級緩存中取數據,如果沒有便查詢數據庫
在這裏插入圖片描述
update之前先清掉一級緩存

一級緩存的不足:

使用一級緩存的時候,因爲緩存不能跨會話共享,不同的會話之間對於相同的數據可能有不一樣的緩存。在有多個會話或者分佈式環境下,會存在髒數據的問題。如果要解決這個問題,就要用到二級緩存。MyBatis 一級緩存(MyBaits 稱其爲 Local Cache)無法關閉,但是有兩種級別可選:

session 級別的緩存,在同一個 sqlSession 內,對同樣的查詢將不再查詢數據庫,直接從緩存中。
1.statement 級別的緩存,避坑: 爲了避免這個問題,可以將一級緩存的級別設爲
2. statement 級別的,這樣每次查詢結束都會清掉一級緩存。

二級緩存:
  二級緩存是用來解決一級緩存不能跨會話共享的問題的,範圍是namespace 級別的,可以被多個SqlSession 共享(只要是同一個接口裏面的相同方法,都可以共享),生命週期和應用同步。如果你的MyBatis使用了二級緩存,並且你的Mapper和select語句也配置使用了二級緩存,那麼在執行select查詢的時候,MyBatis會先從二級緩存中取輸入,其次纔是一級緩存,即MyBatis查詢數據的順序是:二級緩存 —> 一級緩存 —> 數據庫。

作爲一個作用範圍更廣的緩存,它肯定是在SqlSession 的外層,否則不可能被多個SqlSession 共享。而一級緩存是在SqlSession 內部的,所以第一個問題,肯定是工作在一級緩存之前,也就是隻有取不到二級緩存的情況下才到一個會話中去取一級緩存。第二個問題,二級緩存放在哪個對象中維護呢? 要跨會話共享的話,SqlSession 本身和它裏面的BaseExecutor 已經滿足不了需求了,那我們應該在BaseExecutor 之外創建一個對象。

實際上MyBatis 用了一個裝飾器的類來維護,就是CachingExecutor。如果啓用了二級緩存,MyBatis 在創建Executor 對象的時候會對Executor 進行裝飾。CachingExecutor 對於查詢請求,會判斷二級緩存是否有緩存結果,如果有就直接返回,如果沒有委派交給真正的查詢器Executor 實現類,比如SimpleExecutor 來執行查詢,再走到一級緩存的流程。最後會把結果緩存起來,並且返回給用戶
  圖示如下:
  在這裏插入圖片描述
  相應的對應的代碼
  在這裏插入圖片描述

二級緩存的開啓

第一步: 配置文件,現在mybatis版本默認是開啓的:所以直接沒有設置成false就可以不用處理
在這裏插入圖片描述
第二步:
在這裏插入圖片描述

<cache type="org.apache.ibatis.cache.impl.PerpetualCache"
		   size="1024"
		   eviction="LRU"
		   flushInterval="120000"
		   readOnly="false"/>

在這裏插入圖片描述

注:二級緩存是事務性的。這意味着,當 SqlSession 完成並提交時,或是完成並回滾,但沒有執行 flushCache=true 的 insert/delete/update 語句時,緩存會獲得更新。

只要cacheEnabled=true 基本執行器就會被裝飾。有沒有配置,決定了在啓動的時候會不會創建這個mapper 的Cache 對象,只是最終會影響到CachingExecutorquery 方法裏面的判斷。如果某些查詢方法對數據的實時性要求很高,不需要二級緩存,怎麼辦?我們可以在單個Statement ID 上顯式關閉二級緩存(默認是true):

<select useCache="false"></select>

1、事務不提交,二級緩存不存在
這個我測試的時候就遇到二級緩存不起作用的問題就是沒用執行sqlsession.commit()

爲什麼事務不提交,二級緩存不生效?因爲二級緩存使用TransactionalCacheManager(TCM)來管理,最後又調用了TransactionalCache 的getObject()、putObject 和commit()方法,TransactionalCache裏面又持有了真正的Cache 對象,比如是經過層層裝飾的PerpetualCache。在putObject 的時候,只是添加到了entriesToAddOnCommit 裏面,只有它的commit()方法被調用的時候纔會調用flushPendingEntries()真正寫入緩存。它就是在DefaultSqlSession 調用commit()的時候被調用的。

  1. 什麼時候開啓二級緩存?

一級緩存默認是打開的,二級緩存需要配置纔可以開啓。那麼我們必須思考一個問題,在什麼情況下才有必要去開啓二級緩存?

  • 因爲所有的增刪改都會刷新二級緩存,導致二級緩存失效,所以適合在查詢爲主的應用中使用,比如歷史交易、歷史訂單的查詢。否則緩存就失去了意義。
  • 如果多個namespace 中有針對於同一個表的操作,比如Blog 表,如果在一個namespace 中刷新了緩存,另一個namespace 中沒有刷新,就會出現讀到髒數據的情況。所以,推薦在一個Mapper 裏面只操作單表的情況使用。
    在這裏插入圖片描述

集成第三方cache ehcache

除了MyBatis 自帶的二級緩存之外,我們也可以通過實現Cache 接口來自定義二級緩存。MyBatis 官方提供了一些第三方緩存集成方式很多,比如ehcache ,redis等等
mybatis-ehcache

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章