以下场景均在Spring Boot程序中,并非手动创建
SqlSession
使用。
在回答这个问题之前,我们先来回顾一下,Mybatis的一级二级缓存是啥。
一级二级缓存
是什么
- 一级缓存(本地缓存):一级缓存是SqlSession级别的缓存,当我们执行查询时,MyBatis会先将查询结果放在当前SqlSession的缓存中,如果后续有相同的查询,MyBatis会直接从缓存中取出结果,而不会再次执行 SQL 查询。
- 二级缓存(全局缓存):二级缓存是 Mapper 级别的缓存,它可以被多个SqlSession共享。当一个SqlSession 查询数据时,MyBatis会先在一级缓存中查找,如果没有找到,再去二级缓存中查找,如果还没有找到,最后才会去数据库查询。
缓存类型 | 生命周期 | 如何开启 | 位置 |
---|---|---|---|
一级缓存 | 随SqlSession的生命周期 | 默认启用,无法关闭 | BaseExecutor 的localCache 参数中 |
二级缓存 | 跟随程序的生命周期 | xml文件标识<cache/> 或者使用@CacheNamespace 注解 |
MappedStatement 中的cache 参数 |
问题
回到问题本身,其实就是一个缓存生命周期的回答,是否每次都会使用呢?
并不是,得看是如何使用的。有两种情况:
- 显式使用
SqlSession
:在查询后,没有显式调用clearCache
并且在同一个上下文二次查询后,缓存使用。
java
try (SqlSession session = sqlSessionFactory.openSession()) {
// 第一次查询,将结果放入缓存
session.select();
// 第二次查询,直接使用上一次的搜索结果
session.select();
// 清除缓存
session.clearCache();
}
- 由Spring容器管理的
SqlSession
:在Spring中,每次调用Mapper
的方法都会创建一个新的SqlSession
,自然而然也不会使用缓存了。当然,开启了事务另说。
题外话
有没有什么额外回答能在回答的时候加一下分呢?
那么我们就要想想在什么场景下,使用了上一次的搜索结果会有问题呢?
没错就是它:数据库的事务隔离级别
在MySQL中不同的事务隔离级别 对查询起着不同的影响 。
其中在可重复读(REPEATABLE READ)以下的级别都会受到Mybatis 一级二级缓存的影响。那么为什么呢?
读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)都可以在事务查询时获取到其他事务的结果,所以如果使用了Mybatis的缓存 的话,就跟数据库的查询结果不一致了。