Skip to content

一级缓存与二级缓存

一、基础概念补充

1. 什么是作用域?

作用域指缓存数据的有效范围,决定了缓存数据在什么场景下可以被复用。

2. 什么是SqlSession?什么是session级别?

  • SqlSession:MyBatis与数据库的会话对象,封装了执行SQL的所有方法,每次数据库操作创建一个新会话,用完关闭。
  • session级别:缓存数据的有效范围为单个SqlSession会话,会话关闭后缓存数据清空。

3. 平常项目中一二级缓存用得多不多?

  • 一级缓存:默认开启,项目中普遍存在,但开发者通常无感知;
  • 二级缓存:因存在跨会话脏读风险、序列化要求、多表关联场景缓存失效等问题,实际项目中使用较少,更多使用Redis等第三方缓存替代。

二、一级缓存

1. 核心特性

  • 本质:基于PerpetualCacheHashMap本地缓存;
  • 作用域: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. 核心特性

  • 本质:基于PerpetualCacheHashMap存储;
  • 作用域:Namespace/Mapper级别,作用于整个Mapper命名空间,不依赖单个SqlSession;
  • 开启状态:默认关闭,需手动配置;
  • 开启步骤:
    1. 核心配置:<setting name="cacheEnabled" value="true"/>
    2. Mapper映射文件:添加<cache/>标签;
  • 数据转移:只有会话提交或关闭后,一级缓存数据才会转移到二级缓存;
  • 失效条件:
    • 作用域内执行增/删/改操作,该命名空间下所有缓存清空;
    • 缓存数据需实现Serializable接口。

四、一级缓存 vs 二级缓存

特性一级缓存二级缓存
作用域单个SqlSession会话整个Mapper命名空间
开启状态默认开启默认关闭,需手动配置
存储位置本地内存本地内存(可配置第三方缓存)
生命周期会话期间有效,关闭后清空跨会话有效,直到增删改操作清空
依赖对象SqlSession不依赖单个SqlSession

面试相关问题

  1. 问:MyBatis一级缓存和二级缓存的区别是什么?答: 核心区别在于作用域:一级缓存是Session级别,仅在单个会话内有效,默认开启;二级缓存是Namespace级别,跨会话有效,默认关闭,需手动配置。此外,二级缓存数据需实现序列化,且只有会话提交或关闭后才会从一级缓存转移到二级缓存。

  2. 问:二级缓存的注意事项有哪些?答: 1. 缓存数据需实现Serializable接口;2. 作用域内增删改操作会清空该命名空间下所有缓存;3. 数据只有会话提交或关闭后才会转移到二级缓存;4. 存在跨会话脏读风险,实际项目中使用较少。

  3. 问:为什么实际项目中二级缓存用得少?答: 二级缓存存在以下问题:1. 跨会话脏读风险,不同会话间数据更新可能导致缓存不一致;2. 多表关联查询时,任一关联表更新都会导致缓存失效;3. 序列化要求增加开发成本;4. 性能和扩展性不如Redis等第三方缓存。

  4. 问:一级缓存什么时候会失效?答: 一级缓存在以下场景失效:1. 会话调用flush()close()方法;2. 会话中执行增/删/改操作;3. 手动调用clearCache()方法。

Powered by VitePress 1.6.4 | 持续更新中