Mybatis一級緩存和二級緩存 Redis緩存


一級緩存

  • Mybatis的一級緩存存放在SqlSession的生命周期,在同一個SqlSession中查詢時,Mybatis會把執行的方法和參數通過算法生成緩存的鍵值,將鍵值和查詢結果存入一個Map對象中。
  • 如果同一個SqlSession中執行的方法和參數完全一致,那么通過算法會生成相同的鍵值,當Map緩存對象中已經存在改鍵值時,則會返回緩存中的對象。(一個SqlSession連續兩次查詢 得到的是同一個java對象)
  • 任何的insert update delete操作都會清空一級緩存(增刪改任何記錄都會清空當前SqlSession的緩存)。

Spring整合Mybatis的時候一級緩存的問題:

  在未開啟事物的情況之下,每次查詢,spring都會關閉舊的sqlSession而創建新的sqlSession,因此此時的一級緩存是沒有啟作用的

  在開啟事物的情況之下,spring使用threadLocal獲取當前資源綁定同一個sqlSession,因此此時一級緩存是有效的

Spring結合Mybatis一級緩存失效的問題

二級緩存

每個sqlSession都有自己的一級緩存,多個sqlSession共享二級緩存

Mybatis二級緩存可以理解為存在SqlSessionFactory的生命周期

開啟二級緩存(還有全局的開啟方式,這里就不多說了):

1.在對應的XXXMapper.XML添加如下代碼

  <cache></cache>

2. 在對應的select標簽上添加(測試了下 不加也行)

useCache="true"

二級緩存特點:

SqlSession1調用getMapper獲取對象user1

SqlSession1調用getMapper獲取對象user2

user1和user2是同一個實例(原理同一級緩存)

如果二級配置可讀寫的緩存 <cache readOnly="false"/>(顧名思義 可以寫的緩存嗎 就是我寫這個對象 不影響你,兩個實例),不同SqlSession之間通過序列化和反序列化來保證通過緩存獲取數據。

當另外一個SqlSess2開始執行SQL時候,不會去查數據庫 會利用SqlSession1的緩存

SqlSession2調用getMapper獲取對象user1_

SqlSession2調用getMapper獲取對象user2_

user1_和user2_就是反序列化得到的結果 是不同的實例

此時雖然只發出一個SQL 但是:user1==user2  user1_<>user2_<>user1

當 readOnly="true"的時候

<cache readOnly="true"/>

user1==user2==user1==user2

二級緩存坑的地方:

你在OrderMapper.XML 和 UserMapp.XML的文件 都操作了User表的話,

當你使用OrderMapper.XML的SQL更新User表的時候,其他的SeqSession在OrderMapper.XML可以查到User表最新的數據,但是在UserMapp.XML查不到最新的數據

原因就是 二級緩存是基於某個XXXMapper.xml,每個Mapper直接獨立,所以 不同Mapper操作同一張表的時候  使用二級緩存會造成臟讀 

這也就是沒什么人開啟二級緩存的主要原因 

Redis緩存一致性

Mybatis默認提供的緩存是基於Map實現的內存緩存,已經可以基本滿足應用。但當需要緩存大量數據的時候可以使用Redis緩存數據庫來保存Mybatis的二級緩存數據。

但MySQL和Redis是兩個事物,不好做強一致性。

簡單點:可以延時雙刪+過期時間保證最終一致性。

雙刪的原因是防止並發情況下 update_db的過程中 其他事物發現redis緩存是空 重新賦予了Redis的值 此時如果賦值 是錯誤的數據

第二次延時刪除的原因是要考慮MySQL數據庫主從同步的耗時(如果立即刪除 有別的線程從MySQL的從庫查到的數據放到Redis中 此時的從庫可能是沒同步的錯誤數據)

rm_redis
update_db
sleep xxx ms
rm_redis

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM