网站首页 > 技术文章 正文
在当今互联网软件开发领域,性能优化始终是开发者们关注的重点。MyBatis 作为一款广泛使用的 Java 持久层框架,其缓存机制为提升应用性能提供了有力支持。通过缓存,我们能够减少对数据库的频繁访问,从而显著提高系统的响应速度和整体性能。接下来,让我们一同深入探究 MyBatis 中的缓存机制。
MyBatis 缓存初相识
想象一下,你每天上班都要去公司附近的咖啡店买咖啡。第一天,你点了一杯拿铁,咖啡店需要现做,花费了一些时间。但第二天,当你再次点同样的拿铁时,店员直接从准备好的 “缓存” 中拿给你,瞬间就完成了交易。MyBatis 的缓存机制就如同这家咖啡店的 “缓存策略”。当应用程序通过 MyBatis 发起查询时,MyBatis 会先去缓存中查找是否有符合条件的结果。如果有,就直接从缓存中获取数据返回给应用程序,无需再次查询数据库;若没有,则查询数据库,然后将结果存入缓存,以便下次使用。
一级缓存:SqlSession 的贴心助手
(一)一级缓存的作用范围与特点
一级缓存也被称为本地缓存,它是 MyBatis 中默认开启的缓存,作用域为 SqlSession 级别。这意味着,在同一个 SqlSession 执行相同的 SQL 查询时,MyBatis 会从一级缓存中获取结果,而不是再次访问数据库。其生命周期与 SqlSession 相同,当 SqlSession 关闭时,对应的一级缓存也会被清空。
从存储方式来看,一级缓存是基于 PerpetualCache 和 HashMap 实现的,它将查询结果以键值对的形式存储,其中键为 SQL 语句的字符串及其参数,值为查询结果。
(二)一级缓存的失效条件
- 数据修改操作:在 SqlSession 中,一旦执行了 INSERT、UPDATE、DELETE 操作,为了确保数据的一致性,一级缓存会被清空。因为这些操作可能会使原本缓存的数据变得不再准确。
- 手动清空缓存:开发者可以调用 SqlSession.clearCache () 方法手动清空一级缓存。
- SqlSession 关闭:当 SqlSession 关闭后,一级缓存也随之失效。
(三)一级缓存的示例代码
SqlSession session = sqlSessionFactory.openSession();
User user1 = session.selectOne("selectUserById", 1); // 从数据库查询
User user2 = session.selectOne("selectUserById", 1); // 从一级缓存中获取结果
在上述代码中,第一次查询时,由于缓存中没有数据,MyBatis 会查询数据库,并将结果存入一级缓存。第二次执行相同查询时,MyBatis 发现一级缓存中有符合条件的数据,便直接从缓存中获取,大大提高了查询效率。
(四)一级缓存的适用场景
用户会话场景:在 Web 应用中,每个用户的会话都是独立的。如果用户在会话期间多次请求相同的数据,例如用户在浏览商品详情页时,可能多次请求商品信息,一级缓存可以确保这些请求不需要每次都查询数据库,从而提高性能。
批量操作场景:在进行批量插入或更新操作时,一级缓存可以帮助我们减少数据库的访问次数。例如,在一个订单系统中,当用户下单后,系统需要批量插入订单详情,一级缓存可以缓存这些插入操作的结果,减少数据库的压力。
二级缓存:Mapper 级别的性能利器
(一)二级缓存的作用范围与特点
二级缓存是基于 Mapper 级别的缓存,它可以在多个 SqlSession 之间共享缓存数据。即只要是同一个 Mapper 的查询,都可以使用二级缓存中的数据。与一级缓存不同,二级缓存默认是关闭的,需要在配置文件或 Mapper 文件中显式开启。
由于二级缓存是跨 SqlSession 的,所以缓存对象必须实现 Serializable 接口,以便进行序列化存储。而且,只有在事务提交后,查询结果才会写入二级缓存。
(二)二级缓存的失效条件
与一级缓存类似,当执行 INSERT、UPDATE、DELETE 等修改操作时,二级缓存中对应 namespace 下的缓存会被清空。因为这些操作可能导致相关数据发生变化,缓存中的数据不再准确。
(三)启用二级缓存的步骤
在 MyBatis 全局配置文件中启用二级缓存:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
在具体的 Mapper 文件中配置二级缓存:
<mapper namespace="com.example.mapper.UserMapper">
<!-- 启用二级缓存 -->
<cache />
<select id="selectUserById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
确保实体类实现 Serializable 接口:因为缓存数据需要进行序列化存储,所以实体类必须实现 Serializable 接口。例如:
public class User implements Serializable {
private int id;
private String name;
// Getters and Setters
}
(四)二级缓存的示例代码
// 第一次查询,结果存入二级缓存
try (SqlSession session1 = sqlSessionFactory.openSession()) {
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.selectUserById(1);
}
// 第二次查询,不同的SqlSession实例,结果从二级缓存中获取
try (SqlSession session2 = sqlSessionFactory.openSession()) {
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectUserById(1);
}
在上述代码中,第一次查询时,由于二级缓存中没有数据,MyBatis 会查询数据库,并将结果存入二级缓存。第二次使用不同的 SqlSession 进行相同查询时,MyBatis 会直接从二级缓存中获取数据,减少了数据库的访问次数。
(五)二级缓存的适用场景
读多写少的业务场景:对于那些读操作远多于写操作的业务,二级缓存可以显著提高性能。例如,一个新闻网站,新闻内容一旦发布,就会被频繁地读取,但更新频率较低。通过二级缓存,可以在多个用户请求时提供快速的数据访问。
分布式系统场景:在分布式系统中,不同服务可能会访问相同的数据。二级缓存可以跨服务共享,减少对数据库的访问压力。例如,在微服务架构中,用户服务和订单服务可能都需要访问商品信息,通过二级缓存,可以确保这些服务访问的是相同的数据,同时减少数据库的负载。
数据一致性要求不高的业务场景:对于那些对数据一致性要求不高的业务,二级缓存可以提供更快的读取速度。例如,一些统计数据或报表数据,它们不需要实时更新,但需要快速读取,二级缓存可以满足这种需求。
一级缓存与二级缓存的比较
特性 | 一级缓存 | 二级缓存 |
作用范围 | SqlSession 级别 | Mapper 映射器级别,跨 SqlSession |
默认状态 | 默认开启 | 默认关闭 |
缓存生命周期 | 与 SqlSession 相同 | 与 Mapper 相同 |
缓存失效 | SqlSession 执行写操作时清空 | Mapper 执行写操作时清空 |
缓存共享 | 不同的 SqlSession 之间不共享 | 不同的 SqlSession 之间共享 |
存储要求 | 无特殊要求 | 缓存对象需实现 Serializable 接口 |
配置和管理二级缓存
MyBatis 为我们提供了多种方式来配置和管理二级缓存,以满足不同的业务需求。
(一)缓存策略
可以通过<cache>标签的eviction属性配置缓存回收策略。默认使用 LRU(最近最少使用)策略,即移除最长时间不被使用的对象。此外,还有其他选项:
- FIFO(先进先出):按对象进入缓存的顺序移除,先进入缓存的对象先被移除。
- SOFT(软引用):基于垃圾收集器状态和软引用规则移除对象,在内存不足时,软引用关联的对象会被回收。
- WEAK(弱引用):更积极地移除对象,同样基于垃圾收集器状态和弱引用规则,只要垃圾收集器扫描到弱引用关联的对象,就会回收它。
(二)刷新间隔
通过flushInterval属性配置缓存的刷新间隔,单位为毫秒。默认情况下不会自动刷新,我们可以根据业务需求设置合适的刷新间隔,例如:
<cache eviction="LRU" flushInterval="60000" />
上述配置表示每 60000 毫秒(即 1 分钟)自动刷新一次缓存。
(三)缓存大小
通过size属性设置缓存的最大对象数量。例如:
<cache eviction="LRU" flushInterval="60000" size="1024" />
这表示该缓存最多可以存储 1024 个对象,当缓存达到这个数量后,再添加新对象时,会根据缓存回收策略移除一些旧对象。
(四)只读模式
通过readOnly属性设置缓存是否为只读模式。当设置为true时,缓存中的对象在缓存期间不可修改,这样可以提高并发性能,因为多个线程可以共享同一个缓存对象,而无需担心数据冲突。例如:
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true" />
总结
MyBatis 的缓存机制为我们提供了强大的性能优化手段。一级缓存基于 SqlSession,适用于在同一个会话中的多次查询,能有效减少数据库访问次数;二级缓存基于 Mapper,可在多个会话间共享缓存数据,尤其适用于读多写少的业务场景以及分布式系统。通过合理配置和管理缓存,我们能够显著提升应用程序的性能,降低数据库负载,为用户提供更流畅、高效的服务体验。在实际开发中,我们应根据业务需求和数据特点,灵活运用 MyBatis 的缓存机制,让我们的应用程序在性能方面更上一层楼。
猜你喜欢
- 2025-10-19 SpringBoot反复读取Body失效?Wrapper缓存方案一次根治!
- 2025-10-19 今天聊聊 HTTP 缓存控制_http 缓存设置
- 2025-10-19 如何使用 Nginx 缓存提高网站性能 ?
- 2025-10-19 Nginx缓存实战:如何让性能飙升10倍!
- 2025-10-19 一次HTTP强缓存失效引发的浏览器缓存键深度探索
- 2025-10-19 前端缓存破局:gulp-rev实现静态资源hash化全指南
- 2025-01-12 CDN+OpenResty 实现丝滑访问的登录态缓存站
- 2025-01-12 如何在Spring Boot中通过布隆过滤器防止缓存穿透问题?
- 2025-01-12 HTML5缓存机制浅析:移动端Web加载性能优化
- 2025-01-12 如何在 NGINX 中缓存内容
你 发表评论:
欢迎- 最近发表
-
- Python常用标准库(pickle序列化和JSON序列化)
- Linux json-c使用_linux解析json数据
- 源码推荐(03.04):微信支付的测试,Json数据解析
- 打开JSON文件的六种方法,总有一种适合你
- springmvc项目中接收Android提交json数据
- 一篇文章让你详细了解何为JSON_json到底是什么
- FlinkSQL处理复杂JSON的思路_flinksql解析json数组
- 超级好用的轻量级JSON处理命令jq_json使用教程
- .NET性能系列文章二:Newtonsoft.Json vs System.Text.Json
- 推荐几个开发必备的JSON工具_推荐几个开发必备的json工具
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- Oracle RAC (76)
- oracle恢复 (77)
- oracle 删除表 (52)
- oracle 用户名 (80)
- oracle 工具 (55)
- oracle 内存 (55)
- oracle 导出表 (62)
- oracle约束 (54)
- oracle 中文 (51)
- oracle链接 (54)
- oracle的函数 (58)
- oracle面试 (55)
- 前端调试 (52)
本文暂时没有评论,来添加一个吧(●'◡'●)