一级缓存:
先看一个示例:
@Test
public void test (){
SqlSession sqlSession= sqlSessionFactory.openSession();
GmGoodsMapper gmGoodsMapper = sqlSession.getMapper(GmGoodsMapper.class);
System.out.println("==============第一次查询==================");
System.out.println(gmGoodsMapper.findAllById(1));
System.out.println("==============第二次查询==================");
System.out.println(gmGoodsMapper.findAllById(1));
}
在配置文件yml中开启sql日志打印功能:
logging:
level:
com.dongsq.datasource.mapper:
debug
接下来执行测试用例,可以看到:
从打印的结果来看,第二次查询没有打印preparing后面的sql语句,也就是并没有执行这个sql却把结果打印出来了,说明结果已经缓存了。
接下来修改mybatis中的配置,加上flushCache="true":
<select id="findAllById" flushCache="true" resultType="com.dongsq.datasource.entity.GmGoods">
select * from gm_goods where id= #{id}
</select>
再看一下打印的结果:
这样就两次都执行了sql,没有走缓存。
说明:mybatis一级缓存是默认开启的,flushCache="false",关闭一级缓存只需设置flushCache="true"即可,它的意思表示在执行sql之前,清除一级缓存。
修改一下测试代码,修改flushCache="false",然后用两个不同的sqlSession去查询:
@Test
public void test (){
SqlSession sqlSession1= sqlSessionFactory.openSession();
GmGoodsMapper gmGoodsMapper1 = sqlSession1.getMapper(GmGoodsMapper.class);
SqlSession sqlSession2= sqlSessionFactory.openSession();
GmGoodsMapper gmGoodsMapper2 = sqlSession2.getMapper(GmGoodsMapper.class);
System.out.println("==============第一次查询==================");
System.out.println(gmGoodsMapper1.findAllById(1));
System.out.println("==============第二次查询==================");
System.out.println(gmGoodsMapper2.findAllById(1));
}
可以看到结果:
说明:
1、一级缓存只跟sqlSession相关,两个不同的sqlSession不能共享一级缓存。在同一个sqlSession中查询时,Mybatis会把执行的方法和参数通过算法生成缓存的键值,将键值和查询结果存入一个Map对象中,如果同一个sqlSession中执行的方法和参数完全一致,那么通过算法会生成相同的键值,当Map缓存对象中已经存在该键值时,则会返回缓存中的对象,任何的INSERT,UPDATE,DELETE操作都会清空一级缓存。
2、一级缓存在分布式的情况下可能存在问题,两个不同的节点,一个查询,一个修改。
---------------------------------------------------------------------------------------------------------------------------------
二级缓存:
1、二级缓存存在于sqlSessionFactory的生命周期中,可以理解为跨sqlSession,缓存时以namespace为单位的,不同的namespace下操作互不影响。
2、参数cacheEnabled,这个参数是二级缓存的全局开关,默认值是true,如果把这个设置为false,即使后面的二级缓存配置,也不会生效。
接下来开启二级缓存:
1、yml中配置:
mybatis:
configuration:
cache-enabled: true
2、在mapper文件中配置<cache/>标签,和useCache="true"表示开启二级缓存,如果useCache没有配置,则会根据标签是不是select来判断useCache的值是true还是false。
3、java代码中做以下修改,只有commit操作后,才会将数据刷到二级缓存中。
看下同一个sqlSessionFactory,两个不同的sqlSession的查询结果:
可以看到,开启二级缓存后会打印命中率(查询了两次,其中一次走的二级缓存,所以命中率是0.5),第一次没有走缓存,执行的sql,第二次没有打印sql,直接在二级缓存中取得数据。
最后强调一点:二级缓存慎用