深入理解MyBatis缓存机制:一二级缓存全解析(二)


引言

在上一篇文章中,我们深入探讨了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接口和MappedStatementCache属性。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>