一級緩存
- Mybatis的一級緩存存放在SqlSession的生命周期,在同一個SqlSession中查詢時,Mybatis會把執行的方法和參數通過算法生成緩存的鍵值,將鍵值和查詢結果存入一個Map對象中。
- 如果同一個SqlSession中執行的方法和參數完全一致,那么通過算法會生成相同的鍵值,當Map緩存對象中已經存在改鍵值時,則會返回緩存中的對象。(一個SqlSession連續兩次查詢 得到的是同一個java對象)
- 任何的insert update delete操作都會清空一級緩存(增刪改任何記錄都會清空當前SqlSession的緩存)。
Spring整合Mybatis的時候一級緩存的問題:
在未開啟事物的情況之下,每次查詢,spring都會關閉舊的sqlSession而創建新的sqlSession,因此此時的一級緩存是沒有啟作用的
在開啟事物的情況之下,spring使用threadLocal獲取當前資源綁定同一個sqlSession,因此此時一級緩存是有效的
二級緩存
每個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
