一级缓存
一级缓存是SqlSession级别的,SqlSessionFactory在openSession的时候会创建一个本地缓存变量。
相关源码
// org.apache.ibatis.session.defaults.DefaultSqlSessionFactory public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } // 创建SqlSession private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 创建执行器 final Executor executor = configuration.newExecutor(tx, execType); return new DefaultSqlSession(configuration, executor, autoCommit); ... } // 根据配置类的执行器类型创建执行器 public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; } // SimpleExecutor public SimpleExecutor(Configuration configuration, Transaction transaction) { super(configuration, transaction); } // BaseExecutor protected BaseExecutor(Configuration configuration, Transaction transaction) { this.transaction = transaction; this.deferredLoads = new ConcurrentLinkedQueue<>(); // 一级缓存 this.localCache = new PerpetualCache("LocalCache"); this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache"); this.closed = false; this.configuration = configuration; this.wrapper = this; } // PerpetualCache public class PerpetualCache implements Cache { private final String id; private final Map<Object, Object> cache = new HashMap<>(); } // 执行查询时 public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ... List<E> list; try { queryStack++; list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } ... // LocalCacheScope设置为STATEMENT,一级缓存不会生效 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { clearLocalCache(); } return list; } // 查询数据库并放入缓存 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; }
说明
- 默认开启。
- localCacheScope设置为STATEMENT时,sqlSession执行多次查询时每次查询结束后都会清空一级缓存。
- 缓存的key与Namespance、SQL语句相关。
- 一级缓存和执行器类一对一。
二级缓存
与一级缓存的区别
- 二级缓存是应用级别的缓存, 与Configuration类一对一。
- 缓存的key是MapperXML的Namespace,Value和一级缓存的类(PerpetualCache)一样。
- SqlSession事务提交(或关闭)的时候才会存二级缓存,而一级缓存在查询到结果后就存缓存了;但是执行查询时优先从二级缓存中获取查询结果,未命中二级缓存后,才会去一级缓存中获取结果。
启用二级缓存
- 修改settings
<setting name="cacheEnabled" value="true" />
- 修改MapperXML
<cache />
二级缓存失效
- 同一命名空间,执行了增删改时,会清空缓存。当存在联合查询时,可以通过设置
<cache-ref namespace="" />
清空指定命名空间的的二级缓存,但是只能指定一个namespace。