二级缓存

MyBatis 大家都知道有,一级缓存、二级缓存,不过很多人不知道具体的实现,和怎么扩展。

二级缓存

二级缓存,也可以称为 第三者缓存/外部缓存

代码如下:

// BaseExecutor
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 生产 BoundSql,里面包含sql模板和需要的参数
BoundSql boundSql = ms.getBoundSql(parameter);
// 生产cacheKey,用于二级缓存
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

说明:

  • BoundSql 里面就是 sql 模板和 sql 需要的参数 ,根据这个生产 CacheKey (这也是为什么,sql 完全一样,参数不一样的时候,不能命中缓存的原因)。

  • query 方法里面就会去检查缓存了,根据 CacheKey

检查缓存 query 方法
// 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;
}

说明:

  • 可以看到 localCache.getObject 这里,根据我们生产的 CacheKey 获取对应的缓存,不存在就去 查询数据库
  • 注意、注意、注意:二级缓存生效时间是事物提交后,在一个 SqlSession 操作中,完全一样的操作也不会命中二级缓存的,事物没有提交前,同一个操作只会命中一级缓存。

完结~

菜单

  1. 二级缓存,CacheKey 是怎么生成的?
  2. 二级缓存,为什么执行的是一个 Sql,只是参数不一样不能命中缓存?
  3. 二级缓存,完全一样的操作,为什么不能命中缓存?