引言
在上一篇文章中,我们深入探讨了MyBatis的一级缓存和二级缓存的基本概念、工作原理及配置方法。一级缓存作为默认的本地缓存,在单个SqlSession内有效,能显著减少重复查询数据库的开销;而二级缓存则提供了跨SqlSession的全局缓存能力,通过共享数据进一步提升系统性能。本文将延续这一主题,聚焦于缓存的源码实现、性能调优策略、常见问题解决方案以及实战应用场景,帮助开发者更全面地掌握MyBatis缓存机制,并在实际项目中灵活运用。
一、缓存源码实现深度解析
1. 一级缓存的源码剖析
一级缓存的实现核心在于SqlSession内部的Executor组件。MyBatis通过BaseExecutor类管理一级缓存,其关键方法包括query()和update()。当执行查询操作时,Executor会生成一个CacheKey,该CacheKey基于SQL语句、参数、返回类型等信息生成,确保唯一性。如果缓存中存在该CacheKey对应的结果,则直接返回;否则,执行数据库查询并将结果存入缓存。
public class BaseExecutor implements Executor {
protected SqlSession sqlSession;
protected List<ResultSetHandler> resultHandlers;
protected List<ResultHandler> resultHandlers;
protected List<ResultMap> resultMaps;
// ...其他属性省略
public <E> List<E> query(StatementHandler handler, ResultSetHandler rsh, ResultHandler<?> resultHandler, Object[] params) {
List<E> list;
if (this.localCacheScope == LOCAL_CACHE_SCOPE.STATEMENT) {
// 清空本地缓存
this.localCache.clear();
}
list = rsh.getResultList(handler, params);
if (this.localCacheScope == LOCAL_CACHE_SCOPE.STATEMENT) {
// 清空本地缓存
this.localCache.clear();
}
return list;
}
}
关键点解析:
localCacheScope:控制一级缓存的作用范围,SESSION表示缓存仅在当前SqlSession有效,STATEMENT表示缓存仅对当前执行的语句有效。localCache:一级缓存的存储容器,是一个HashMap,以CacheKey为键,查询结果为值。缓存清空时机:执行
update方法或手动调用clearCache()时,一级缓存会被清空。
2. 二级缓存的源码剖析
二级缓存的实现涉及Mapper级别的Cache接口和MappedStatement的Cache属性。MyBatis通过BaseCache类提供二级缓存的默认实现,支持LRU(最近最少使用)算法。
public interface Cache {
int getId();
void putObject(Object key, Object value);
Object getObject(Object key);
void clear();
int getSize();
long getLastAccessTime();
void setProperties(Properties props);
String getCacheKey();
}
public class BaseCache implements Cache {
protected int size;
protected long timeToLiveSeconds;
protected long timeToIdleSeconds;
protected boolean readOnly;
protected CacheDelegate delegate;
protected List<Cache> listeners;
protected List<Cache> evictors;
protected List<Cache> flushers;
protected List<Cache> writers;
protected List<Cache> readers;
protected List<Cache> updaters;
protected List<Cache> removers;
protected List<Cache> creators;
protected List<Cache> destroyers;
protected List<Cache> clearers;
protected List<Cache> reloaders;
protected List<Cache> reloadersOnFlush;
protected List<Cache> reloadersOnClear;
protected List<Cache> reloadersOnEvict;
protected List<Cache> reloadersOnFlushAndClear;
protected List<Cache> reloadersOnFlushAndEvict;
protected List<Cache> reloadersOnClearAndEvict;
protected List<Cache> reloadersOnFlushAndClearAndEvict;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReload;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlush;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClear;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvict;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReload;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlush;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClear;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvict;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReload;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlush;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClear;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvict;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReload;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlush;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClear;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvict;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReload;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlush;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClear;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvict;
protected List<Cache> reloadersOnFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReloadAndFlushAndClearAndEvictAndReload;
protected List<Cache>