回顾一下mybatis一级缓存

281 阅读2分钟

前言

mybatis 默认开启一级缓存,为什么我们很少遇到缓存带来的问题呢;我工作6年也只遇到过一次,最近才遇到的,并且我还记录了:不懂myabits缓存引发的问题这篇文章主要是记录当时排查这个问题的过程。今天这篇文主要回顾一下一级缓存的知识。

什么时候会查询缓存(同时满足)

  1. 相同的 namespace(同一个命名空间,即同一个 Mapper 文件),执行相同的Mapper方法
  2. 相同的 SQL 参数;
  3. 在同一个会话SqlSession当中;

什么时候会清空缓存

  1. 不能够在查询之前执行clearCache
  2. 中间不能执行任何updatedeleteinsert操作(否则会将SqlSession中的数据全部清空)。

关键代码BaseExecutor

看一下执行查询和更新的关键代码吧,代码中关键地方我也写了注释的。

query 代码

1.mapperStatment 可以配置是否刷新缓存
2.查询完成之后,会根据设置的缓存作用域对缓存进行处理,如果作用域是Statement,就会调用clearLocalCache方法

@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  // 判断是否刷新缓存,默认否
  if (queryStack == 0 && ms.isFlushCacheRequired()) {
    clearLocalCache();
  }
  List<E> list;
  try {
    queryStack++;
    // 如果为null,就是localCache里面查询,localCache 的实现类是PerpetualCache.class,里面的代码非常简单就是维护了一个HashMap

    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--;
  }
  if (queryStack == 0) {
    for (DeferredLoad deferredLoad : deferredLoads) {
      deferredLoad.load();
    }
    // issue #601
    deferredLoads.clear();
    // 判断缓存范围 默认是Session会话级别
    if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
      // issue #482
      clearLocalCache();
    }
  }
  return list;
}

update 代码

  1. 进入方法是就先执行的clearLocalCache方法
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
  if (closed) {
    throw new ExecutorException("Executor was closed.");
  }
  clearLocalCache();
  return doUpdate(ms, parameter);
}

有疑惑的地方,或者我有写的不对地方 欢迎大家批评指正