zl程序教程

您现在的位置是:首页 >  后端

当前栏目

mybatis一级缓存(session cache)引发的问题

mybatis缓存 session cache 引发 一级 问题
2023-09-14 09:03:16 时间
最近项目功能单元测试中,出现了一个奇怪的bug。远程调试发现,程序进行了2次相同的查询,返回了实体类(ClassA)的2个对象:classAInstance1和classAInstance2,当修改classAInstance1.property1时,竟然classAInstance2.property1也被改了!!! 很快发现classAInstan

最近项目功能单元测试中,出现了一个奇怪的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做查询,所以这个情况下一级缓存是生效的
Mybatis的一级缓存和二级缓存的理解以及用法 先了解一下缓存的概念:原始意义是指访问速度比一般随机存取存储器快的一种RAM,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。对于我们编程来说,所谓的缓存,就是将程序或系统经常要调用的对象(临时数据)存在内存中,以便其使用时可以快速调用,不必再去创建新的重复的实例。这样做可以减少系统的开销,提高效率。
Java Spring Boot开发实战系列课程【第6讲】:Spring Boot 2.0实战MyBatis与优化(Java面试题) 立即下载