实现mybatis自定义缓存需实现cache接口的getid、putobject、getobject、removeobject、clear五个方法,保证线程安全(推荐readwritelock),正确处理cachekey类型缓存键,并在mapper中通过或@options配置启用。

实现 MyBatis 自定义缓存,核心是让自定义类实现 org.apache.ibatis.cache.Cache 接口,并在 Mapper 中正确启用。这不是配置开关就能生效的“即插即用”,而是需要手动编写缓存逻辑、处理线程安全、生命周期和缓存键值管理。
必须实现的 Cache 接口方法
MyBatis 通过调用以下五个关键方法控制缓存行为,缺一不可:
- getId():返回唯一标识(通常就是 Mapper 的 namespace),MyBatis 用它区分不同 Mapper 的缓存空间
- putObject(Object key, Object value):将查询结果存入缓存,需确保序列化/反序列化正确(尤其用 Redis 时)
- getObject(Object key):根据缓存 key 查找并返回对象,注意 null 值处理(MyBatis 认为 null 表示未命中)
- removeObject(Object key):执行更新/删除操作时清掉对应缓存项(如 flushCache="true" 的 update 语句触发)
- clear():清空整个 namespace 下的缓存,比如执行 commit 后或手动调用 SqlSession.clearCache()
线程安全与读写锁不能省
MyBatis 可能并发访问同一个 Cache 实例,所以必须保证多线程下数据一致。官方推荐使用 ReadWriteLock(如 ReentrantReadWriteLock)保护共享资源:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 读操作(
getObject)用 readLock,允许多个线程同时读 - 写操作(
putObject、removeObject、clear)用 writeLock,互斥执行 - 不要用 synchronized 方法块——性能差,且无法满足 MyBatis 对锁粒度的要求
缓存键(key)不是简单字符串
MyBatis 传入的 key 是 CacheKey 类型对象,它封装了 Statement ID、SQL、参数、分页信息等,具备自动 hash 和 equals 能力:
- 直接用
key.toString()或key.hashCode()作为缓存键是常见做法(Redis/Ehcache 场景下) - 不建议自己拼接 SQL + 参数字符串——容易忽略参数顺序、null 处理、分页 offset 等细节,导致缓存错乱
- 若用 Redis,可加统一前缀(如
"mybatis:" + namespace + ":" + key.toString())避免键冲突
集成到 Mapper 的具体步骤
光写好 Cache 类还不够,必须显式启用:
- Mapper XML 中添加
<cache type="com.example.MyRedisCache"></cache>(type 指向你的实现类全限定名) - Mapper 接口方法上标注
@Options(useCache = true)(默认开启,但更新语句要设useCache = false) - 确保该 Mapper 的所有 select 语句没有设置
flushCache="true"(否则每次查都清缓存) - 全局开关开启:MyBatis 配置中
<settings><setting name="cacheEnabled" value="true"></setting></settings>
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










