主题切换
一级缓存与二级缓存
一、基础概念补充
1. 什么是作用域?
作用域指缓存数据的有效范围,决定了缓存数据在什么场景下可以被复用。
2. 什么是SqlSession?什么是session级别?
- SqlSession:MyBatis与数据库的会话对象,封装了执行SQL的所有方法,每次数据库操作创建一个新会话,用完关闭。
- session级别:缓存数据的有效范围为单个SqlSession会话,会话关闭后缓存数据清空。
3. 平常项目中一二级缓存用得多不多?
- 一级缓存:默认开启,项目中普遍存在,但开发者通常无感知;
- 二级缓存:因存在跨会话脏读风险、序列化要求、多表关联场景缓存失效等问题,实际项目中使用较少,更多使用Redis等第三方缓存替代。
二、一级缓存
1. 核心特性
- 本质:基于
PerpetualCache的HashMap本地缓存; - 作用域:Session级别,仅在单个SqlSession会话内有效;
- 开启状态:默认开启;
- 失效条件:
- 会话调用
flush()、close()方法; - 会话中执行了增/删/改操作;
- 手动调用
clearCache()方法。
- 会话调用
2. 示例说明
java
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper1 = sqlSession.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession.getMapper(UserMapper.class);
// 第一次查询,执行SQL并缓存结果
User user = userMapper1.selectById(6);
// 第二次查询,直接从一级缓存读取,不执行SQL
User user1 = userMapper2.selectById(6);
sqlSession.close(); // 会话关闭,一级缓存清空三、二级缓存
1. 核心特性
- 本质:基于
PerpetualCache的HashMap存储; - 作用域:Namespace/Mapper级别,作用于整个Mapper命名空间,不依赖单个SqlSession;
- 开启状态:默认关闭,需手动配置;
- 开启步骤:
- 核心配置:
<setting name="cacheEnabled" value="true"/> - Mapper映射文件:添加
<cache/>标签;
- 核心配置:
- 数据转移:只有会话提交或关闭后,一级缓存数据才会转移到二级缓存;
- 失效条件:
- 作用域内执行增/删/改操作,该命名空间下所有缓存清空;
- 缓存数据需实现
Serializable接口。
四、一级缓存 vs 二级缓存
| 特性 | 一级缓存 | 二级缓存 |
|---|---|---|
| 作用域 | 单个SqlSession会话 | 整个Mapper命名空间 |
| 开启状态 | 默认开启 | 默认关闭,需手动配置 |
| 存储位置 | 本地内存 | 本地内存(可配置第三方缓存) |
| 生命周期 | 会话期间有效,关闭后清空 | 跨会话有效,直到增删改操作清空 |
| 依赖对象 | SqlSession | 不依赖单个SqlSession |
面试相关问题
问:MyBatis一级缓存和二级缓存的区别是什么?答: 核心区别在于作用域:一级缓存是Session级别,仅在单个会话内有效,默认开启;二级缓存是Namespace级别,跨会话有效,默认关闭,需手动配置。此外,二级缓存数据需实现序列化,且只有会话提交或关闭后才会从一级缓存转移到二级缓存。
问:二级缓存的注意事项有哪些?答: 1. 缓存数据需实现
Serializable接口;2. 作用域内增删改操作会清空该命名空间下所有缓存;3. 数据只有会话提交或关闭后才会转移到二级缓存;4. 存在跨会话脏读风险,实际项目中使用较少。问:为什么实际项目中二级缓存用得少?答: 二级缓存存在以下问题:1. 跨会话脏读风险,不同会话间数据更新可能导致缓存不一致;2. 多表关联查询时,任一关联表更新都会导致缓存失效;3. 序列化要求增加开发成本;4. 性能和扩展性不如Redis等第三方缓存。
问:一级缓存什么时候会失效?答: 一级缓存在以下场景失效:1. 会话调用
flush()、close()方法;2. 会话中执行增/删/改操作;3. 手动调用clearCache()方法。