MyBatis:一级缓存和二级缓存
·
为什么要有缓存?
缓存是为了提高数据库查询速度,在查询时先走缓存,缓存是在内存中的,缓存没有命中时,再进行数据库的查询(磁盘IO)。
类似于计算机组成原理的cache,频繁访问的内容放在cache中会大幅度提高运作效率
一级缓存(默认开启)
一级缓存是sqlsession级别的缓存,在单个session中,反复查询数据库的时候会先走缓存,若二级缓存开启,则先走二级缓存,再走一级缓存。若二级缓存关闭,则直接走一级缓存。
二级缓存(默认关闭)
作用域边界:Mapper 的 namespace(命名空间)
每个 namespace 对应一个独立的二级缓存区域,不同 namespace 的缓存互不干扰;
即使两个 Mapper(比如 UserMapper 和 OrderMapper)查询同一张数据库表,只要 namespace 不同,它们的二级缓存也不会共享数据;
全局图

二级缓存导致脏读的情况
在进行联表查询的时候,查询结果会缓存在多个表里(查询出来的所有字段都会存储,就算字段不属于这个表而是属于连接后的大表)
但是若其中一个表更新后,只会清理那一个namespace的缓存区域
导致查询其他表的时候,依旧走二级缓存命中,查出旧的信息,产生脏读

一般用Redis代替二级缓存
清空一级缓存的方式

Select元素的flushCache设置为true方便一些
清空二级缓存的方式
1、二级缓存的生命周期和 SqlSessionFactory 一致,只要 SqlSessionFactory 不被销毁(比如应用不重启),缓存就会存在(除非手动清理或触发自动淘汰);
手动清理:
public class MyBatisCacheCleaner {
// 注入Spring管理的SqlSessionFactory
@Resource
private SqlSessionFactory sqlSessionFactory;
/**
* 清理指定namespace的二级缓存
* @param namespace Mapper的命名空间(如:com.example.mapper.UserMapper)
*/
public void clearCacheByNamespace(String namespace) {
// 1. 获取MyBatis全局配置
Configuration configuration = sqlSessionFactory.getConfiguration();
// 2. 根据namespace获取对应的缓存对象
org.apache.ibatis.cache.Cache cache = configuration.getCache(namespace);
if (cache != null) {
// 3. 手动清理该namespace的二级缓存
cache.clear();
System.out.println("成功清理namespace [" + namespace + "] 的二级缓存");
} else {
System.out.println("未找到namespace [" + namespace + "] 的缓存配置");
}
}
}
2、当执行增删改操作时,MyBatis 会默认清空当前 namespace 下的所有二级缓存,避免缓存数据与数据库不一致。
更多推荐


所有评论(0)