一篇读懂--mybatis的缓存

一篇读懂–mybatis的缓存

MyBatis的缓存指的是缓存查询结果,当以后使用相同的sql语句、传入相同的参数进行查询时,可直接从mybatis本地缓存中获取查询结果,而不必查询数据库。

mybatis的缓存包括一级缓存、二级缓存,一级缓存默认是开启的,二级缓存默认是关闭的。

一级缓存:
一篇读懂--mybatis的缓存_第1张图片

SqlSession级别:在SqlSession中有一个Map,key是由sql语句、参数等信息组成的唯一值,value是查询出来的结果对象。
好处: 减小数据库压力
如何失效 :只要此sqlSession调用了、、这些会修改数据库的元素,就会清空此sqlSession的一级缓存,不管有没有使用commit()提交。
举例:

        User user1 = mapper.queryUserById(1);
        User user2 = mapper.queryUserById(1);

第一次查询时,就将查询结果放到一级缓存中。
如果后续使用的sql语句相同、传入的实参也相同,则结果对象也会相同,直接从一级缓存中获取结果对象,不再查询数据库。

        User user1 = mapper.queryUserById(1);
        sqlSession.commit();
        User user2 = mapper.queryUserById(1);

如果此sqlSession调用了commit()方法,会自动清空此sqlSession的一级缓存。
因为使用commit(),会将修改提交到数据库,下一次相同的查询,查询结果可能变了,之前的一级缓存不能再用,所以会自动清空。

下面用spring整合mybatis来测试一下mybatis的一级缓存:
1、下面是service层实现, 可以看到,我两次查询了同一个数据,理论上由于mybatis中默认开启一级缓存, 那么第二次肯定时要从缓存中获取,而不是创建SqlSession对象重新从数据库获取:

@Autowired
private LsjmUserMapper lsjmUserMapper;
 
@Override
public LsjmUser getUser() {
	// 第一次查询
	LsjmUser user = lsjmUserMapper.getUserByName("300");
	System.out.println(user.toString());
	
	// 第二次查询
	LsjmUser user1 = lsjmUserMapper.getUserByName("300");
	System.out.println(user1.toString());
	return user;
}

从日志信息可以很明显的看到,代码中的两次查询构建了两个SqlSession对象,也就是说第二次查询并没有从前一次的SqlSession缓存中获取,而是自己新建一个SQLSession对象,重新查询;这样看来,一级缓存好像失效了?
一篇读懂--mybatis的缓存_第2张图片
这是为什么呢?因为我们没有加@Transaction注解
spring 中 结合 mybatis中,默认情况下,数据库处于自动提交模式,每一条sql语句处于一个单独的事务中,语句执行完毕时,如果执行成功则隐式提交事务。而mybatis的一级缓存在这种情况下是无效的,想要一级缓存起作用,则要开启事务:

开启事务: spring使用ThreadLocal获取当前资源绑定同一个SQLSession

未开启事务:每次查询,spring关闭旧的SslSession,创建一个新的Sqlsession对象,一级缓存补气作用

还有一种特殊情况,也会调用到缓存:

        ProcessDef list = processMapper.selectByPrimaryKey(5L);
        list.setCode("123");
        ProcessDef list1 = processMapper.selectByPrimaryKey(5L);

(注意,上面这个方法要加上@Transaction注解)
像上面这种情况,有时候在代码中也会出现,然后你就会找bug找半天都找不出问题;
结果是:list1的结果中的Code字段是“123”,而不是数据库中的那个字段!是不是不可思议,你可以自己在本地试试,事实就是如此。
原因是什么呢? 上面第一次查询直接去数据库查,这个可以理解, list.setCode(“123”);之后,第一次查询出来的缓存就已经变了,其中code字段就变成123了,所以这也是list1中code字段为123的原因!(这种情况大家要留意一下,搞了我半天的时间去找bug)
二级缓存:
mapper级别,同一个namespace下的mapper,有一个Map。
一篇读懂--mybatis的缓存_第3张图片

SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1 = mapper1.queryUserById(1);
        System.out.println(user1);

        SqlSession sqlSession2 = MyBatisUtils.getSqlSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.queryUserById(1);
        System.out.println(user2);

不使用二级缓存,会执行2次查询。
一篇读懂--mybatis的缓存_第4张图片

你可能感兴趣的:(mybatis缓存)