mybatis緩存機制

Mybatis提供一級緩存,二級緩存和自定義緩存:


一級緩存是SqlSession級別,其最大的共享範圍就是一個SqlSession內部,如果多個SqlSession之間需要共享緩存,則需要使用到二級緩存。默認情況下,mybatis 的一級緩存是開啓的。

二級緩存是mapper級別的緩存,對於mapper級別的緩存不同的sqlsession是可以共享的。

一.一級緩存

 如下圖所示,MyBatis會在一個SqlSession對象中創建一個本地緩存(local cache),對於每一次查詢,都會嘗試根據查詢的條件去本地緩存中查找是否在緩存中,如果在緩存中,就直接從緩存中取出,然後返回給用戶,從而減少資源浪費;否則,從數據庫讀取數據,將查詢結果存入緩存並返回給用戶,session關閉,緩存將被清空。


Mybatis一級緩存默認開啓,無需配置。

測試案例1

運行結果:

可以看到同一個sqlSession兩次查詢只是發出了一條sql語句,第二次查詢是從緩存中讀取。

第二個newSqlSession查詢的時候也是發出了sql語句,因爲緩存已經被清空了,由此可見mybatis一級緩存的sqlsession是不共享的

測試案例2

測試結果:

第一步 查詢發起sql語句,並將查詢結果放入緩存,

第二步對該語句進行更新操作,緩存將被清空

第三步再次查詢信息,該語句又發起一次sql語句。

二.二級緩存

二級緩存可以使用MyBatis自己定義的二級緩存實現;也可以通過實現Cache接口自定義緩存(使用第三方內存緩存庫,如redis)。

1.   MyBatis自定義的二級緩存工作機制:


a).特點:即鬆散的Cache緩存管理和維護

一個Mapper中定義的增刪改查操作只能影響到自己關聯的Cache對象,如圖所示namespace1產生的緩存只會被放置到相應關聯的Cache1中,即Mappernamespace2,namespace3,namespace4 中的CRUD的語句不會影響到Cache1。

b).Mapper之間的緩存關係比較鬆散,相互關聯的程度比較弱

如果將AMapper和BMapper共用一個Cache對象,當BMapper執行更新操作時,可以清空對應Cache中的所有的緩存數據,使緩存使用效率變的很低!AMapper和BMapper的任意的更新操作都會將共用的Cache清空,會頻繁地清空Cache,導致Cache實際的命中率和使用率就會變得很低,這種策略實際情況下是不可取的。

相關配置:

SqlSessionFactory層面上的二級緩存是不開啓的,二級緩存開啓需要配置。

1.使用註解@CacheNamespace方式配置,不寫type就使用mybatis默認的緩存,也可以去實現 Cache 接口來自定義緩存
   
@CacheNamespace註解詳情:
Implementation: 實現緩存功能的類
PerpetualCache這個類是mybatis默認實現二級緩存功能的類
Eviction:緩存回收策略(可選值有"LRU"、"FIFO"、"SOFT"、"WEAK",默認值是LRU
LruCache:最近最少使用,移除最長時間不被使用的對象.

FIFO:先進先出,按對象進入緩存的順序來移除

SOFT:軟引用,移除基於垃圾回收器狀態和軟引用規則的對象

WEAK:弱引用,更積極地移除基於垃圾收集器狀態和弱引用規則的對象

flushInterval: 指緩存過期時間,單位爲毫秒.
默認爲0,即只要容量足夠,永不過期
Size:指緩存多少個對象
默認值爲1024
readWrite:可讀/可寫
默認爲true
Bloking:鎖
默認爲false
2.對於MyBatis自帶二級緩存,實體類可以不用實現序列化接口。

測試案例1:

測試結果:

創建兩個sqlSession對象,

第一次查詢發出sql語句,將查詢結果翻入緩存中,關閉第一個sqlsession,用第二個sqlsession發起查詢,數據是從緩存中讀取的,由此可見mybatis二級緩存sqlSession之間是共享的.

測試案例2:

測試結果:

第一步sqlSessionOne進行sql查詢操作,將查詢結果放入緩存中

第二步sqlSessionTwo執行更新操作,緩存將被清空

第三步sqlSessionThree進行查詢操作,重新發起sql查詢。

執行更新操作,二級緩存數據將被清空

三.自定義緩存Redis

爲了提高擴展性。MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來自定義二級緩存,通過重寫Cache接口中的方法,將mybatis中默認的緩存空間映射到redis空間中。

相關配置:

自定義類MybatisCache通過重寫Cache接口中的方法,自定義緩存.

 


flashInterval:指緩存過期時間,單位爲毫秒,60000即爲60秒 

 2.自定義緩存redis有時會將數據緩存到硬盤上需要實現 Serializable 序列化接口


開啓了二級緩存後,還需要將要緩存的pojo實現Serializable接口,爲了將緩存數據取出執行反序列化操作,因爲二級緩存數據存儲介質多種多樣,不一定只存在內存中,有可能存在硬盤中,如果我們要再取這個緩存的話,就需要反序列化了。所以mybatis中的pojo需要實現Serializable接口。

測試案例1:

測試結果:

第一步sqlSessionOne進行sql查詢操作,將查詢結果放入redis緩存中

 

Redis查看結果,數據已被序列化:

第二步sqlSessionTwo執行更新操作,緩存將被清空

Redis查看結果:

第三步sqlSessionThree進行查詢操作,重新發起sql查詢。

執行更新操作,二級緩存redis數據將被清空

打開Redis查看結果:

 

禁用二級緩存使用@Options註解,將useCache屬性設置爲false

options有個timeout

mybatis如果不指定,默認超時時間是不做限制的,默認值爲-1.

以秒爲單位,當超出了設置的超時時間時,會拋出SQLTimeoutException

#爲什麼不用mybatis原生態緩存?

因爲mybatis原生態緩存有侷限性,mybaits的二級緩存區域是以mapper爲單位劃分,比如某列表使用了join鏈接查詢,當對其中一個表(做了增刪改操作)數據發生變動時,會將cache全部清空,從而倒導致cache實際命中率和使用率變低,這種策略不符合我們的業務場景。

測試案例1,使用mybatis原生態緩存:

測試結果,多次修改表1,表2數據始終使用sql查詢:

測試案例2,使用redis緩存:

需註釋掉cache接口的清空緩存clear()方法,因爲每次增刪改都清空緩存會消耗緩存的內存資源

測試結果:

1.     第一次執行聯表查詢將數據放入到緩存中,後對錶1進行更新操作,對錶2執行sql查詢,發現數據是從緩存中讀取。


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