Mybatis缓存机制
在 MyBatis 中,缓存分为 一级缓存 和 二级缓存。它们的作用是减少数据库查询次数,提高性能。然而,在某些情况下,缓存会失效或被清空。
一、一级缓存(sqlSession 级别缓存)
1. 一级缓存的基本特性
- 一级缓存默认开启,作用范围是
SqlSession
的生命周期。 - 在同一个
SqlSession
内,如果两次查询条件完全相同且没有发生更新操作,则第二次查询会直接从缓存中获取结果。
2. 一级缓存失效情形
以下情况会导致一级缓存失效:
-
SqlSession
关闭或提交事务后- 当
SqlSession
被关闭或提交事务时,一级缓存会被清空。 - 示例:
sqlSession.commit(); // 提交事务后,一级缓存失效 sqlSession.close(); // 关闭 SqlSession 后,一级缓存失效
- 当
-
执行了增删改操作
- 如果在同一个
SqlSession
中执行了insert
、update
或delete
操作,MyBatis 会清空一级缓存。 - 原因:这些操作可能会影响表中的数据,导致缓存中的数据与数据库不一致。
- 如果在同一个
-
手动调用
clearCache()
方法- 开发者可以手动调用
sqlSession.clearCache()
来清空当前SqlSession
的一级缓存。
- 开发者可以手动调用
-
查询条件不同
- 如果两次查询的条件不同(即使只差一个参数),MyBatis 不会使用缓存。
-
查询间隔过长
- 如果两次查询之间的时间间隔超过了 MyBatis 的缓存刷新时间(默认无限制),缓存可能会失效。
二、二级缓存(Mapper 级别缓存)
1. 二级缓存的基本特性
- 二级缓存的作用范围是整个 Mapper 文件(即命名空间
namespace
),多个SqlSession
可以共享同一个二级缓存。 - 默认情况下,二级缓存需要手动配置才能启用。
2. 配置二级缓存
<!-- 在 Mapper 文件中启用二级缓存 -->
<cache />
3. 二级缓存失效情形
以下情况会导致二级缓存失效:
-
未启用二级缓存
- 如果未在 Mapper 文件中配置
<cache>
标签,或者未在全局配置文件中启用二级缓存(settings.cacheEnabled=true
),则不会使用二级缓存。
- 如果未在 Mapper 文件中配置
-
Mapper 方法未设置
useCache=true
- 默认情况下,查询方法会使用二级缓存。如果将
useCache
设置为false
,则该方法不会使用二级缓存。 - 示例:
<select id="findUserById" resultType="User" useCache="false"> SELECT * FROM users WHERE id = #{id} </select>
- 默认情况下,查询方法会使用二级缓存。如果将
-
Mapper 方法设置了
flushCache=true
- 如果查询方法设置了
flushCache=true
,则每次执行该方法时都会清空二级缓存。 - 示例:
<select id="findUserById" resultType="User" flushCache="true"> SELECT * FROM users WHERE id = #{id} </select>
- 如果查询方法设置了
-
执行了增删改操作
- 如果在同一个 Mapper 中执行了
insert
、update
或delete
操作,默认会清空该 Mapper 的二级缓存。 - 示例:
<update id="updateUser"> UPDATE users SET name = #{name} WHERE id = #{id} </update>
- 如果在同一个 Mapper 中执行了
-
手动调用
clearCache()
方法- 可以通过
sqlSession.clearCache()
清空当前SqlSession
的一级缓存和二级缓存。
- 可以通过
-
缓存策略冲突
- 如果多个 Mapper 文件共享同一个二级缓存,但它们的缓存策略(如 LRU、FIFO 等)不一致,可能导致缓存失效。
-
缓存超时
- 如果设置了缓存的过期时间(通过
<cache>
标签的eviction
属性),当缓存数据超过设定时间后会被清除。 - 示例:
<cache eviction="LRU" flushInterval="60000" /> <!-- 缓存每 60 秒刷新一次 -->
- 如果设置了缓存的过期时间(通过
-
跨命名空间访问
- 如果两个不同的 Mapper 文件共享同一个二级缓存,但在其中一个 Mapper 中发生了增删改操作,另一个 Mapper 的缓存也会被清空。
-
自定义缓存实现问题
- 如果实现了自定义缓存(通过
<cache-ref>
或自定义Cache
接口),但逻辑有问题,可能导致缓存失效。
- 如果实现了自定义缓存(通过
三、总结
缓存类型 | 失效情形 |
---|---|
一级缓存 | 1. 2. 执行增删改操作 3. 手动调用 4. 查询条件不同 5. 查询间隔过长 |
二级缓存 | 1. 未启用二级缓存 2. 3. 4. 执行增删改操作 5. 手动调用 6. 缓存策略冲突 7. 缓存超时 8. 跨命名空间访问 9. 自定义缓存实现问题 |
了解这些缓存失效的情形有助于更好地控制缓存行为,避免因缓存不一致导致的数据错误。