Mybatis源码学习笔记之Mybatis二级缓存

简介

  Mybatis一级缓存是会话级的缓存,而二级缓存则是应用级别的缓存,默认关闭,二级缓存使用不慎可能会导致脏读。

开启方式(SpringBoot+Mybatis)

  application.properties添加配置

mybatis.configuration.cache-enabled=true

  在mapper的xml文件中的namespace中加上

<cache></cache>

  为了方便看到效果 ,application.properties设置日志级别为debug

logging.com.qs.birp.dao=debug
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

  先测试调用一次SQL ,再次调用时可以缓存命中。

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3563659a] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.qs.birp.dao.EquTAufkDao]: 0.3333333333333333
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3563659a]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d18d986] was not registered for synchronization because synchronization is not active
Cache Hit Ratio [com.qs.birp.dao.EquTAufkDao]: 0.5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d18d986]

命中条件

  和一级缓存不同,二级缓存在事务提交和会话关闭后才会写入(在会话和二级缓存间会有一个事务缓存管理器TransactionalCacheManager,会话期间查询的数据会放到管理器的暂存区TransactionalCache,当事务提交后才会写入到指定的二级缓存区域),当执行数据库update操作时会清空该namespace下的缓存。

  1. 相同的statement id
  2. 相同的Sql与参数
  3. 查询结果分页条件相同
  4. 没有使用ResultHandler来自定义返回数据
  5. 没有配置UseCache=false 来关闭指定查询的缓存
  6. 没有配置FlushCache=true 来清空缓存
  7. 在调用存储过程中不能使用出参,即Parameter中mode=out|inout

源码解析

  源码位置:org.apache.ibatis.executor.CachingExecutor.java 这里面比较关键的代码是List list = (List) tcm.getObject(cache, key);

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    Cache cache = ms.getCache();
    if (cache != null) {
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

  Mybatis源码里面二级缓存使用装饰器的设计模式,装饰器在org.apache.ibatis.cache.decorators包下面。
Mybatis源码学习笔记之Mybatis二级缓存_第1张图片

  SynchronizedCache 同步锁,用于保证对指定缓存区的操作都是同步的
  LoggingCache 统计器,记录缓存命中率
  BlockingCache 阻塞器,基于key加锁,防止缓存穿透
  ScheduledCache 时效检查,用于验证缓存有效器,并清除无效数据
  LruCache 溢出算法,最近最少使用算法,淘汰闲置最久的缓存。
  FifoCache 溢出算法,淘汰加入时间最久的缓存
  WeakCache 溢出算法,基于java弱引用规则淘汰缓存
  SoftCache 溢出算法,基于java软引用规则淘汰缓存
  PerpetualCache 实际存储,内部采用HashMap进行存储。

注意事项

  1. 只能在【只有单表操作】的表上使用缓存
    不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。
  2. 在可以保证查询远远大于insert,update,delete操作的情况下使用缓存

你可能感兴趣的:(Java,java,开发语言,后端,mybatis)