一级缓存,是 MyBatis 中最常用的,也是默认开启的,大家可能没啥感觉,起到的作用很大的,特别是在如今的微服务应用中,可能一个业务下来,同一个查询会有多次,这个时候二级缓存,和一级缓存就可以优化很多性能。
// BaseExecutor@SuppressWarnings("unchecked")@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {// 略...try {// 查询计数++queryStack++;// 一级缓存// tip: localCache 是 PerpetualCache(永久缓存)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);}} finally {queryStack--;}// 略return list;}
说明:
一级缓存,实在 Executor 里面,在 query 的时候回去 localCache.getObject(key)
检查缓存是否存在,存在就直接返回了。
key,是根据我们的 sql 和 sql 参数生成的 key,sql 一样参数不一样的时候,key 也是不一样的。
localCache
是一个 PerpetualCache
永久缓存。
缓存是在执行器里面的,执行器每次 openSession 会创建一个新的,所以每次执行完就销毁了,一次性的。
// BaseExecutorprotected BaseExecutor(Configuration configuration, Transaction transaction) {this.transaction = transaction;this.deferredLoads = new ConcurrentLinkedQueue<>();// 这是一个永不过期缓存,id是给缓存去一个别名this.localCache = new PerpetualCache("LocalCache");// 这是一个永不过期缓存,id是给缓存去一个别名this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");this.closed = false;this.configuration = configuration;this.wrapper = this;}
// DefaultSqlSessionFactoryprivate SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {// 解析 <Environment> 标签配置的属性final Environment environment = configuration.getEnvironment();// 创建 TransactionFactoryfinal TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);// 创建事务tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);// 创建执行器,默认是 CachingExecutorfinal Executor executor = configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);} finally {ErrorContext.instance().reset();}}
说明:
openSession
的时候,都会创建一个新的 Executor
。Executor
又是一个 Plugin proxy 代理对象 , 详细看 Plugin 分析。完结~