一、二级缓存简介
1、简介
2、说明
二级缓存是全局缓存,基于 namespace 级别的缓存,一个 namespace 对应一个二级缓存;
工作机制:
(1)一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
(2)如果当前会话关闭了,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存中的内容;
(3)每一个 namespace 对应一个二级缓存,不同 namespace 查出的数据会放在自己对应的缓存中(map)
1 2 | sqlSession===EmployeeMapper==>Employee DepartmentMapper==>Department |
二、二级缓存的使用步骤
1、全局配置文件中开启二级缓存
1 | <setting name = "cacheEnabled" value= "true" /> 默认是 false (不开启) |
2、在每个 mapper.xml 中配置使用二级缓存 <cache></cache>
二级缓存需要在 mapper.xml 中配置 <cache> 标签,所以二级缓存来说是 映射文件级别的。不管 SqlSession 是怎么创建的,只要是访问的同一个映射文件中的 SQL 语句,就可以被缓存。
3、注意: POJO 需要实现 Serializable 接口
三、二级缓存工作机制
工作机制:
1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2、如果会话关闭:一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
3、不同namespace查出的数据会放在自己对应的缓存中(map), 效果:数据会从二级缓存中获取,查出的数据都会被默认先放在一级缓存中。
4、只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中;
5、如果 sqlSession 没有关闭,还是会从一级缓存查询;
四、二级缓存相关的属性(<cache>标签中的属性)
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" type=""></cache>
(1)cache 开启二级缓存
(2)eviction 缓存的回收策略
1 2 3 4 5 | LRU:最近最少使用的,移除最长时间不被使用的对象。 FIFO:先进先出,按对象进入缓存的顺序来移除它们。 SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。 VEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认的是 LRU。 |
(3)flushInterval 缓存刷新间隔,单位毫秒
缓存多长时间清空一次,默认不清空,设置一个毫秒值
(4)readOnly 是否只读 true/false
(5)size 缓存中存放多少元素,引用数据,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出,还严重消耗内存;太小则没意义;
(6)type:用来设置第三方缓存,指定自定义缓存的全类名;实现cache接口即可。
五、代码示例
1、使用二级缓存
代码:
/**
* 二级缓存
* @throws IOException
*/
@Test
public void testSecondLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
try {
EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
EmployeeMapperCache mapper2 = sqlSession2.getMapper(EmployeeMapperCache.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println("emp01 = " + emp01);
sqlSession.close();
//第二次查询是从二级缓冲中拿到的数据,并没有发送新的SQL
//缓存命中率 Cache Hit Ratio [com.njf.mybatis.dao.EmployeeMapperCache]: 0.5
Employee emp02 = mapper2.getEmpById(1);
System.out.println("emp02 = " + emp02);
sqlSession2.close();
System.out.println(emp01 == emp02);
} finally {
sqlSession.close();
}
}
运行结果:
2、未开启二级缓存
代码:
/**
* 未启用二级缓存
* @throws IOException
*/
@Test
public void testSecondLevelCacheDisable() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
try {
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
DepartmentMapper mapper2 = sqlSession2.getMapper(DepartmentMapper.class);
Department dept01 = mapper.getDeptById(1);
System.out.println("dept01 = " + dept01);
sqlSession.close();
Department dept02 = mapper2.getDeptById(1);
System.out.println("dept02 = " + dept02);
sqlSession2.close();
System.out.println(dept01 == dept02);
} finally {
sqlSession.close();
sqlSession2.close();
}
}
运行结果:
可以看到发送了两条SQL语句,正是因为没有使用二级缓存,当第一个 sqlSession 关闭后,没有把查询结果放在二级缓存中,所以再次查询时会重新发送 SQL 语句。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?