MyBatis中的缓存机制

一般的ORM(Object Relational Mapping)框架都会提供缓存功能以减少访问数据库的次数,减轻数据库压力,提高查询效率。MyBatis中有一级和默认实现的二级缓存,而且MyBatis也预留了集成第三方缓存的接口(二级缓存接口的自定义实现)。

先通过一段源码来看看mybatis的查询的执行流程。

1> openSqlSession()->getMapper()->query(),mybatis中最终的执行是交给Executor执行器来执行的,Executor接口的实现类中有一个CachingExecutor类(这是mybatis实现的二级缓存)。

2> 执行query方法

 1 @Override
 2 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
 3     throws SQLException {
 4   //获取缓存对象
 5   Cache cache = ms.getCache();
 6   if (cache != null) {//存在缓存
 7     //尝试刷新缓存,确保缓存是最新
 8     flushCacheIfRequired(ms);
 9     //如果该sql启用缓存并且该查询没有用到ResultHandler
10     if (ms.isUseCache() && resultHandler == null) {
11       //参数检查
12       ensureNoOutParams(ms, boundSql);
13       @SuppressWarnings("unchecked")
14       //从缓存中读取
15       List<E> list = (List<E>) tcm.getObject(cache, key);
16       if (list == null) {//未命中,调用默认执行器执行query
17         list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
18         //查询结果放入缓存
19         tcm.putObject(cache, key, list); // issue #578 and #116
20       }
21       return list;
22     }
23   }
24   return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
25 }

 

通过上面一段代码,可以发现以下两个问题:

  • 首先,大家大概可以猜测出mybatis中一级缓存和二级缓存的优先级顺序了吧?😂没错,在开启二级缓存的情况下会先从二级缓存中读取——>二级缓存未命中的话会调用默认执行器的query方法——>默认执行器再读取自己的一级缓存——>未命中则访问数据库——>查询结果放入缓存。

  • 二级缓存是保存在MappedStatement中的,MappedStatement是用来存放我们的定义DAO层的mapper的信息。一个mapper接口对应一个MappedStatement,那么二级缓存的作用域就是同一mapper下有效。


一级缓存:

mybatis 的一级缓存是sqlSession级别的,缓存作用域是在一次数据库会话中有效。一级缓存是持久化缓存(本地缓存)并且是默认开启的,不需要手动开启。

为什么说一级缓存是Session级别的并且是本地缓存呢?mybatis中每一个sqlSession都会对应一个继承自BaseExecutor的Executor(默认是SimipleExecutor)。而BaseExecutor中存在两个PerpetualCache类型的实现Cache接口的对象,见名知意,它就是一个持久化的缓存对象,具体的持久化实现不多赘述(没看😢)。

  

为了避免脏读,sqlSession执行了DML操作(insert、update、delete),并commit了之后,mybatis会清空当前sqlSession缓存中的所有缓存数据。


二级缓存

从开头的源码解读可以看出,二级缓存的作用域是同一mpper接口,所有的sqlSession查询结果都会走MapperStatement中的Cache。mybatis中的二级缓存默认是关闭的需要手动开启。

开启mybatis二级缓存的方法:

  • 在mybatis配置文件中添加下面的设置

    <settings>
            <setting name="cacheEnabled" value="true"/>
    </settings>
  • 在需要开启二级缓存的mapper.xml文件中添加下面的配置

    <!-- 当前mapper下所有语句开启二级缓存 -->
    <!-- 也可以在对应的mapper接口上添加@CacheNamespace注解 -->
    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>

    具体的执行流程可以看开头的源码解析,不过多赘述 

 

posted on 2021-01-08 17:29  kk_cheng  阅读(163)  评论(0)    收藏  举报