mybatis一級快取(session cache)引發的問題
問題回顧
最近專案功能單元測試中,出現了一個奇怪的bug。遠端除錯發現,程式進行了2次相同的查詢,返回了實體類(ClassA)的2個物件:classAInstance1和classAInstance2,當修改classAInstance1.property1時,竟然classAInstance2.property1也被改了!!! 很快發現classAInstance1和classAInstance2地址是相同的,它們是同一個記憶體物件!
原因分析
經除錯發現,mybatis返回的實體類的記憶體地址是相同的!於是猜測是mybatis快取的原因,於是進行了下面的測試驗證。
測試驗證
經過單元測試驗證,不開啟事務的情況下,多次相同的查詢,返回物件地址不相等, 程式碼略。
經過單元測試驗證,在一個事務內,多次相同的查詢,返回物件地址相等, 程式碼如下:
@Resource
private MybatisSessionCacheTestService mybatisSessionCacheTestService;
@Test
public void test_mybatis_sql_session_cache(){
Long id = 100L;
ClassA classAInstance1 = mybatisSessionCacheTestService.queryById(id);
ClassA classAInstance2 = mybatisSessionCacheTestService.queryById(id);
//assert mybatis cache is on
Assert.assertTrue(classAInstance1 == classAInstance2);
}
@Service
public class MybatisSessionCacheTestService {
@Resource
private ClassADAO classDAO;
@Transactional //spring 事務註解
public ClassA queryById(Long id){
return classADAO.queryById(id);
}
}
解決方案
- 1.把查詢提前到事務之前(之外),這樣只解決了個別問題,解決並不徹底。
- 2.在mybatis的mapper xml裡配置每次清空快取flushCache:
<select id="selectById" resultType="ClassA" flushCache="true">
...
</select>
附錄:mybatis快取介紹
一級快取
即session快取,作用域為 Session,當 Session flush 或 close 之後,該Session中的所有 Cache 就將清空,預設開啟。
注意 整合spring(使用mybatis-spring)時:
- 每次查詢spring會重新建立SqlSession,所以一級快取是不生效的。
- 而當開啟事務時,spring會使用同一個SqlSession做查詢,所以這個情況下一級快取是生效的
二級快取
即全域性快取,其作用域為 Mapper(Namespace),預設關閉。
其他參考:
- mybatis快取 ,簡單介紹了mybatis一級和二級快取,獨立使用mybatis(SqlSession)、以及整合spring(mybatis-spring)的情況下進行了測試
- MyBatis學習總結(七)——Mybatis快取 ,簡單介紹了mybatis一級和二級快取,獨立使用mybatis(SqlSession)進行了測試
- mybatis3 cache 官方文件
附註jar包版本:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
相關文章
- Mybatis 一級快取和引發的問題MyBatis快取
- mybatis二級快取引數MyBatis快取
- MyBatis快取機制(一級快取,二級快取)MyBatis快取
- mybatis快取之一級快取(一)MyBatis快取
- Mybatis的快取——一級快取和原始碼分析MyBatis快取原始碼
- Hibernate一級快取(session)與二級快取(sessionFactory)的知識點。快取Session
- mybatis快取-二級快取MyBatis快取
- mybatis快取之一級快取(二)MyBatis快取
- Mybatis的二級快取MyBatis快取
- 被mybatis一級快取坑了MyBatis快取
- Mybatis的二級快取、使用Redis做二級快取MyBatis快取Redis
- mybatis原始碼學習:一級快取和二級快取分析MyBatis原始碼快取
- 快取問題(一) 快取穿透、快取雪崩、快取併發 核心概念快取穿透
- Mybatis二級快取使用MyBatis快取
- 關於 http cache 的一個小問題以及引發的思考HTTP
- Mybatis 一級快取和二級快取原理區別 (圖文詳解)MyBatis快取
- mybatis原始碼詳細解析(2)---- 一級,二級快取MyBatis原始碼快取
- 快取的問題快取
- 快取問題(四) 快取穿透、快取雪崩、快取併發 解決案例快取穿透
- Mybatis 二級快取應用 (21)MyBatis快取
- Mybatis的快取MyBatis快取
- Mybatis PageHelper編譯SQL引發的一次效能問題.18286262MyBatis編譯SQL
- 配置session——快取Session快取
- Redis快取穿透、快取雪崩、redis併發問題分析Redis快取穿透
- Spring Cache快取框架Spring快取框架
- SpringBoot系列——cache快取Spring Boot快取
- 高併發快取面臨的問題快取
- mybatis基礎系列(四)——關聯查詢、延遲載入、一級快取與二級快取MyBatis快取
- MyBatis 快取MyBatis快取
- MyBatis的快取玩法MyBatis快取
- WebApi和Mvc的Session一直獲取不到問題WebAPIMVCSession
- Mybatis整合二級快取與同時使用快取與事務存在的坑MyBatis快取
- myBatis原始碼解析-二級快取的實現方式MyBatis原始碼快取
- Guava學習:Cache快取Guava快取
- Spring Boot Cache Redis快取Spring BootRedis快取
- Spring Cache快取註解Spring快取
- 一次快取效能問題排查快取
- 聊一聊Integer的快取機制問題快取
- Mybatis一級快取和結合Spring Framework後失效的原始碼探究MyBatis快取SpringFramework原始碼