MyBatis 缓存机制详解
MyBatis 提供了强大的缓存机制来提高数据库访问性能,主要包括一级缓存和二级缓存两种。
一级缓存 (Local Cache)
特性:
- 默认开启,作用域为 SqlSession 级别
- 同一个 SqlSession 中执行相同的 SQL 查询时,会直接从缓存中获取结果
- 执行 INSERT/UPDATE/DELETE 操作或调用
clearCache()
方法时会清空缓存
工作原理:
- 第一次查询后将结果存入 SqlSession 的缓存
- 后续相同查询直接从缓存获取
- 任何更新操作都会清空当前 SqlSession 的缓存
示例:
SqlSession session = sqlSessionFactory.openSession();
try {
// 第一次查询,访问数据库
User user1 = session.selectOne("getUserById", 1);
// 第二次查询,直接从一级缓存获取
User user2 = session.selectOne("getUserById", 1);
// 执行更新操作,清空一级缓存
session.update("updateUser", user1);
// 需要再次访问数据库
User user3 = session.selectOne("getUserById", 1);
} finally {
session.close();
}
二级缓存 (Second Level Cache)
特性:
- 需要手动配置开启,作用域为 Mapper 级别 (Namespace 级别)
- 多个 SqlSession 共享缓存数据
- 缓存数据可以持久化到磁盘或使用第三方缓存实现
配置方式:
- 在 mybatis-config.xml 中启用二级缓存:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- 在 Mapper XML 中配置缓存:
<mapper namespace="com.example.UserMapper">
<cache/>
...
</mapper>
高级缓存配置:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
eviction
:缓存回收策略 (LRU, FIFO, SOFT, WEAK)flushInterval
:刷新间隔(毫秒)size
:缓存对象数量readOnly
:是否只读
注意事项:
- 二级缓存需要实体类实现 Serializable 接口
- 事务提交后(SqlSession关闭后)才会将数据存入二级缓存
- 多表操作可能导致脏读问题
缓存执行顺序
- 先查询二级缓存
- 二级缓存未命中则查询一级缓存
- 一级缓存未命中才查询数据库
自定义缓存
MyBatis 支持集成第三方缓存,如 Ehcache、Redis:
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
缓存最佳实践
- 查询频繁但更新少的表适合使用缓存
- 关联查询复杂的场景慎用二级缓存
- 对实时性要求高的数据考虑设置较短的 flushInterval
- 考虑使用只读缓存提高性能
- 分布式环境建议使用集中式缓存(如Redis)
通过合理配置 MyBatis 缓存,可以显著减少数据库访问,提高系统性能。