浅谈MyBatis二级缓存
一、二级缓存介绍
我们知道MyBatis 提供了一级缓存来减轻数据库的压力,但是一级缓存是一个SqlSession(会话)级别的缓存,这也就意味着一级缓存的适用范围比较小。在一级缓存的基础上,MyBatis 提供了二级缓存机制,二级缓存是一个namespace级别的缓存,相对于一级缓存而言,二级缓存允许跨SqlSession工作,因此二级缓存的作用范围更大。
有关一级缓存可参考博文:
https://blog.csdn.net/codejas/article/details/79545367
二、二级缓存运行机制
每个SqlSession在执行查询操作的时候,都会将查询的结果放在当前会话的一级缓存中。如果当前会话关闭,一级缓存中的数据会被保存在二级缓存中。因此二级缓存是在一级缓存的基础上进行扩展的,不同的namespace查出的数据都会将数据存在自己对应的缓存中,这些缓存信息使用Map存储。
需要注意的地方是:MyBatis 在开启二级缓存的情况下,如果发出了一条SQL 查询语句,会先向二级缓存中查询是否有对应的缓存数据,如果没有再接着查询一级缓存中的数据,如果一级缓存中也没有对应的缓存数据,才会向数据库发送SQL。下面附一张蹩脚的二级缓存运行机制图。
三、实现二级缓存的步骤
1.在MyBatis 全局配置文件中开启二级缓存的配置,默认也是开启的,建议自己设置为开启的。
2.在对应的SQL 映射文件中加入<cache/>标签。
3.将返回的JavaBean 数据类型的类实现Serializable(序列化)接口。
知道了二级缓存的实现方式,下面就来体会一下二级缓存带来的作用。
四、二级缓存初体验
MyBatis 全局配置文件:
1 <!-- 配置二级缓存,默认也是开启的,建议手动设置一下 -->
2 <setting name="cacheEnabled" value="true"/>
POJO 实现序列化接口:
package com.jas.mybatis.bean;
import java.io.Serializable;
public class Department implements Serializable{
private Integer id;
private String departmentName;
//省略get、set 与toString 方法
}
mapper 接口:
Department getDeptById(Integer id);
SQL 映射文件:
<!--
在需要使用二级缓存的SQL 映射文件中添加 <cache/> 标签
相关的一些参数介绍:
eviction:缓存回收策略
flushInterval:缓存刷新时间,单位是毫秒,默认不刷新
size:可存储多少个缓存对象,只能是正整数,合理的设置可以防止内存泄漏
readOnly:是否只读
-->
<cache/>
<select id="getDeptById" resultType="com.jas.mybatis.bean.Department">
SELECT id, dept_name departmentName FROM t_dept WHERE id = #{id}
</select>
测试代码:
// 用于返回SqlSessionFactory 对象
private SqlSessionFactory getSqlSession() throws IOException {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(is);
}
@Test
public void secondLevelTest() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSession();
//创建两个不同的会话
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
DepatmentMapper depatmentMapper1 = sqlSession1.getMapper(DepatmentMapper.class);
DepatmentMapper depatmentMapper2 = sqlSession2.getMapper(DepatmentMapper.class);
Department department1 = depatmentMapper1.getDeptById(1);
System.out.println(department1);
// 关闭当前的会话1, 否则二级缓存不起作用
sqlSession1.close();
Department department2 = depatmentMapper2.getDeptById(1);
System.out.println(department2);
// 关闭会话2
sqlSession2.close();
}
测试结果:
当会话1 查询结束并关闭后,我们使用另一个会话执行与会话1 相同的SQL 查询语句,发现并没有发送SQL 语句,因为缓存中已经保存了要查询的数据,这次直接从缓存中获取数据,这就是MyBatis 提供的跨会话级别(SqlSession)的二级缓存机制。
五、与缓存相关的设置
1.可以在MyBatis 全局配置文件中的setting标签中配置cacheEnabled属性,表示是否启用二级缓存机制,不过不影响一级缓存。
2.select查询标签中可以设置useCache属性,配置是否使用二级缓存,默认一级缓存是一直生效的。
3.sqlSession.clearCache();方法默认只清除一级缓存中的数据。
4.可以在每个增删改的标签中设置flushCache属性,设置为true后,如果执行了该增删改操作,则一级缓存与二级缓存中的数据都会清空。
六、总结
这篇博客主要对MyBatis 中的二级缓存机制做了介绍,在实际开发的过程中,MyBatis 提供的二级缓存机制好像并没有获得开发人员的青睐。原因是二级缓存是一个namespace级别的缓存,如果在不同的namespace下操作同一SQL 语句,可能导致缓存中的数据不正确。在进行多表联查的时候,也可能会导致二级缓存中的数据不正确。所以在实际的开发过程中要慎用二级缓存。
————————————————
版权声明:本文为CSDN博主「留兰香丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/codejas/article/details/79547932
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~