嘿,各位技术探险家们!上回咱们聊了Mybatis一级和二级缓存的“江湖规矩”,但总感觉少了点“内功心法”——源码层面的剖析。今天咱们就深挖Mybatis缓存的底层逻辑,把一级、二级缓存的源码关键路径掰开揉碎,再结合避坑指南,让你彻底告别“缓存玄学”!
*一、一级缓存源码:SqlSession级“小金库”*
*1. 源码入口:*\**BaseExecutor\**
*的*\**query\**
*方法*
// org.apache.ibatis.executor.BaseExecutor.java
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// 1. 先从本地缓存(一级缓存)捞数据
List<E> list = (List<E>) localCache.getObject(key);
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
return list; // 缓存命中,直接返回
}
// 2. 缓存未命中,执行数据库查询
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
return list;
}
*核心逻辑拆解*:
- *缓存存储结构*:
localCache
本质是PerpetualCache
(继承自Cache
接口),底层用HashMap
实现,键是CacheKey
(由SQL+参数+分页等生成),值是查询结果。 - *缓存失效场景*:当执行
insert/update/delete
时,会调用clearLocalCache()
清空缓存(源码在SimpleExecutor
的update
方法中)。
*2. 事务提交时的缓存行为*
// org.apache.ibatis.executor.BaseExecutor.java
@Override
public void commit(boolean required) throws SQLException {
// 一级缓存仅在SqlSession关闭或提交时释放,但不会主动同步到二级缓存
// 若需持久化缓存,需依赖二级缓存机制
}
*关键结论*:
- 一级缓存的生命周期绑定
SqlSession
,仅在单次会话内有效,无法跨会话共享。 - 事务提交不会主动推送缓存到二级缓存(需手动配置
flushCache
或依赖二级缓存机制)。
*二、二级缓存源码:跨会话“共享黑市”*
*1. 开启源码:*\**@CacheNamespace\**
*注解触发器*
// org.apache.ibatis.binding.MapperRegistry.java
public <T> T getMapper