一级缓存

一级缓存,是 MyBatis 中最常用的,也是默认开启的,大家可能没啥感觉,起到的作用很大的,特别是在如今的微服务应用中,可能一个业务下来,同一个查询会有多次,这个时候二级缓存,和一级缓存就可以优化很多性能。

一级缓存
// BaseExecutor
@SuppressWarnings("unchecked")
@Override
public <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 会创建一个新的,所以每次执行完就销毁了,一次性的。

    // BaseExecutor
    protected 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;
    }
    • 执行器的构造方法,每次都会创建一个新的 localCache,执行器销毁,随之销毁。
一级缓存和 SqlSession 关系
// DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 解析 <Environment> 标签配置的属性
final Environment environment = configuration.getEnvironment();
// 创建 TransactionFactory
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 创建事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建执行器,默认是 CachingExecutor
final 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 分析。
  • 大家都说一级缓存,作用域为 sqlSession,不过准确的说是 Executor 才对。

完结~

彩蛋

  1. 一级缓存,作用域是不是 SqlSession 呢?
  2. 一级缓存,是永久的吗?
  3. 一级缓存,什么是否销毁?
  4. 一级缓存,这样才能命中缓存?