网站首页 > 文章精选 正文
一句话总结
MyBatis采用两级缓存机制:
1. 一级缓存:SqlSession级别,默认开启,同一会话中相同查询直接复用缓存结果,执行更新操作或关闭会话时自动清空。
2. 二级缓存:Mapper级别,需手动开启,多个SqlSession共享,通过序列化机制实现跨会话缓存,支持LRU等淘汰策略。
两者均通过装饰器模式实现,可通过接口扩展集成第三方缓存(如Redis)。
详细解析
MyBatis 缓存分为一级缓存和二级缓存,两者在作用范围、生命周期和管理方式上存在显著差异。以下是详细的介绍:
1. 一级缓存(Local Cache)
核心特性
作用范围:SqlSession级别(同一个数据库会话)。
默认开启:无需额外配置。
生命周期:与SqlSession绑定,会话关闭或执行更新操作(增删改)时自动清空。
共享性:仅对当前SqlSession可见,其他会话无法访问。
工作原理
缓存命中:在同一个SqlSession中,若多次执行相同的 SQL 和参数,MyBatis 会直接从缓存中返回结果,避免重复查询数据库。
缓存失效:
执行INSERT、UPDATE、DELETE操作。
手动调用sqlSession.clearCache()。
提交事务(sqlSession.commit())或回滚事务(sqlSession.rollback())。
示例
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询,访问数据库
User user1 = mapper.selectUserById(1);
// 第二次查询,命中一级缓存(不访问数据库)
User user2 = mapper.selectUserById(1);
// 执行更新操作,清空缓存
mapper.updateUser(user1);
sqlSession.commit();
// 第三次查询,缓存已失效,重新访问数据库
User user3 = mapper.selectUserById(1);
sqlSession.close();
2. 二级缓存(Second Level Cache)
核心特性
作用范围:Mapper级别(跨SqlSession)。
手动开启:需在 XML 或注解中显式配置。
生命周期:与应用生命周期一致,直到缓存被主动清除或配置过期。
共享性:多个SqlSession共享同一 Mapper 的缓存。
配置方式
1、全局开启:在mybatis-config.xml中启用二级缓存
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2、Mapper 级配置:在 Mapper XML 中添加<cache/>标签:
<mapper namespace="com.example.UserMapper">
<cache eviction="LRU" flushInterval="60000" size="1024"/>
</mapper>
参数说明:
- eviction:缓存淘汰策略(默认LRU,可选FIFO、SOFT、WEAK)。
- flushInterval:自动刷新间隔(毫秒)。
- size:缓存最大对象数量。
工作原理
- 缓存命中:多个SqlSession执行相同 SQL 时,若二级缓存存在数据,直接返回结果。
- 缓存失效:
执行INSERT、UPDATE、DELETE操作(同一 Mapper)。
手动调用sqlSession.clearCache()或通过配置自动刷新。
示例:
<!-- UserMapper.xml -->
<mapper namespace="com.example.UserMapper">
<cache eviction="LRU"/>
<select id="selectUserById" resultType="User" useCache="true">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
3. 缓存优先级与执行流程
当同时启用一级和二级缓存时,MyBatis 按以下顺序查询数据:
一级缓存:优先检查当前SqlSession的缓存。
二级缓存:若一级缓存未命中,检查二级缓存。
数据库查询:若两级缓存均未命中,执行 SQL 查询,并将结果写入缓存。
4. 缓存使用注意事项
适用场景
一级缓存:适合单次会话内重复查询(如循环中多次查询同一数据)。
二级缓存:适合读多写少且数据实时性要求不高的场景(如配置表、静态数据)。
常见问题
脏读:
若多个SqlSession修改同一数据,二级缓存可能返回过期数据。
解决方案:合理设置flushInterval或在更新操作后手动清除缓存。
序列化问题:
二级缓存默认将对象序列化存储,实体类需实现Serializable接口。
分布式环境:
默认二级缓存是单机缓存,分布式系统中需集成 Redis、Ehcache 等分布式缓存框架。
5. 扩展:自定义缓存
MyBatis 支持集成第三方缓存库(如 Redis、Ehcache)替换默认的 PerpetualCache。
步骤(以 Redis 为例):
添加 Redis 依赖:
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-redis</artifactId>
<version>1.0.0-beta2</version>
</dependency>
配置 Mapper 使用 Redis 缓存:
<mapper namespace="com.example.UserMapper">
<cache type="org.mybatis.caches.redis.RedisCache"/>
</mapper>
猜你喜欢
- 2025-07-28 【MySQL】详解 MySQL 三种日志 ( binlog、redo log 和 undo log ) 及其作用
- 2025-07-28 Rust的数据库框架:SQLx连接MySQL实践
- 2025-07-28 SpringCloud专题 - 分布式事务Seata详解
- 2025-07-28 分库分表后,数据库数据一致性问题如何解决?这操作真的可以
- 2025-07-28 数据库(DBMS)面试题(数据库面试题2020)
- 2025-07-28 支付宝一面:多线程事务怎么回滚?用 @Transactional可以回去了!
- 2025-07-28 什么是实时数据同步?纯干货解读!(什么是实时数据传输)
- 2025-07-28 什么是 SQL 事务,如何创建 SQL 事务
- 2025-07-28 数据库事务类型说明(数据库事务的分类)
- 2025-07-28 Spring Boot 常用注解全解析:20 个高频注解
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)
- mysql数据库面试题 (57)
- fmt.println (52)