一、一级缓存简介
在系统代码的运行中,我们可能会在一个数据库会话中,执行多次查询条件完全相同的Sql,鉴于日常应用的大部分场景都是读多写少,这重复的查询会带来一定的网络开销,同时select查询的量比较大的话,对数据库的性能是有比较大的影响的。Mybatis提供了一级缓存的方案来优化在数据库会话间重复查询的问题。实现的方式是每一个SqlSession中都持有了自己的缓存:
一种是SESSION级别,即在一个Mybatis会话中执行的所有语句,都会共享这一个缓存
一种是STATEMENT级别,可以理解为缓存只对当前执行的这一个statement有效
用一张图来解释一级缓存,如下图:
每一个SqlSession中持有了自己的Executor,每一个Executor中有一个Local Cache。当用户发起查询时,Mybatis会根据当前执行的MappedStatement生成一个key,去Local Cache中查询,如果缓存命中的话,返回。如果缓存没有命中的话,则写入Local Cache,最后返回结果给用户。
二、一级缓存配置
只需要在Mybatis的配置文件中,添加如下语句,就可以使用一级缓存。共有两个选项,SESSION或者STATEMENT,默认是SESSION级别
<setting name="localCacheScope" value="SESSION"/>
注意:spring结合mybatis时一级缓存失效问题
1、在未开启事物的情况之下,每次查询,spring都会关闭旧的sqlSession而创建新的sqlSession,因此此时的一级缓存是没有启作用的
2、在开启事物的情况之下,spring使用threadLocal获取当前资源绑定同一个sqlSession,因此此时一级缓存是有效的
三、一级缓存测试
测试一、
开启一级缓存,范围为会话级别,调用两次selectByPrimaryKey
@Transactional
public void test4() {
User user=userMapper.selectByPrimaryKey(1);
System.out.println(user);
User user2=userMapper.selectByPrimaryKey(1);
System.out.println(user2);
}
我们可以看到,只有第一次真正查询了数据库,后续的查询使用了一级缓存
测试二、
在这次的试验中,我们增加了对数据库的修改操作,验证在一次数据库会话中,对数据库发生了修改操作,一级缓存是否会失效
@Transactional
public void test4() {
User user=userMapper.selectByPrimaryKey(1);
System.out.println(user);
User user3=new User();
user3.setUsername("123");
userMapper.insert(user3);
User user2=userMapper.selectByPrimaryKey(1);
System.out.println(user2);
}
我们可以看到,在修改操作后执行的相同查询,查询了数据库,一级缓存失效。分析:如果是insert/delete/update方法,缓存就会刷新
一级缓存总结:
1、Mybatis一级缓存的生命周期和SqlSession一致。
2、Mybatis的缓存是一个粗粒度的缓存,没有更新缓存和缓存过期的概念,同时只是使用了默认的hashmap,也没有做容量上的限定。
3、Mybatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,有操作数据库写的话,会引起脏数据,建议是把一级缓存的默认级别设定为Statement,即不使用一级缓存。
文章参考:https://www.jianshu.com/p/c553169c5921