千家信息网

总结MyBatis缓存结构

发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,这篇文章主要介绍"总结MyBatis缓存结构",在日常操作中,相信很多人在总结MyBatis缓存结构问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"总结MyBatis缓存
千家信息网最后更新 2025年02月04日总结MyBatis缓存结构

这篇文章主要介绍"总结MyBatis缓存结构",在日常操作中,相信很多人在总结MyBatis缓存结构问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"总结MyBatis缓存结构"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

二级缓存

主要内容:

二级缓存构建在一级缓存之上,在收到查询请求时,MyBatis 首先会查询二级缓存。若二级缓存未命中,再去查询一级缓存。与一级缓存不同,二级缓存和具体的命名空间绑定,一级缓存则是和 SqlSession 绑定。

在按照 MyBatis 规范使用 SqlSession 的情况下,一级缓存不存在并发问题。二级缓存则不然,二级缓存可在多个命名空间间共享。这种情况下,会存在并发问题,因此需要针对性去处理。除了并发问题,二级缓存还存在事务问题。

二级缓存如何开启?

配置项

      

cacheEnabled=true表示二级缓存可用,但是要开启话,需要在Mapper.xml内配置。

或者 简单方式

对配置项属性说明:

  • flushInterval="60000",间隔60秒清空缓存,这个间隔60秒,是被动触发的,而不是定时器轮询的。

  • size=512,表示队列最大512个长度,大于则移除队列最前面的元素,这里的长度指的是CacheKey的个数,默认为1024。

  • readOnly="true",表示任何获取对象的操作,都将返回同一实例对象。如果readOnly="false",则每次返回该对象的拷贝对象,简单说就是序列化复制一份返回。

  • eviction:缓存会使用默认的Least Recently Used(LRU,最近最少使用的)算法来收回。FIFO:First In First Out先进先出队列。

在Configuration类的newExecutor方法中是否开启二级缓存

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {    executorType = executorType == null ? defaultExecutorType : executorType;    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;    Executor executor;    if (ExecutorType.BATCH == executorType) {      executor = new BatchExecutor(this, transaction);    } else if (ExecutorType.REUSE == executorType) {      executor = new ReuseExecutor(this, transaction);    } else {      executor = new SimpleExecutor(this, transaction);    }      //是否开启二级缓存    if (cacheEnabled) {      executor = new CachingExecutor(executor);    }    executor = (Executor) interceptorChain.pluginAll(executor);    return executor;  }

二级缓存通过CachingExecutor来实现的,原理是缓存里存在,就返回,不存在就调用Executor ,如果一级缓存未关闭,则先查一级缓存,不存在,再到数据库中查询。

下面使用一张图来表示:

下面是源码:

@Overridepublic  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {    // 获得 BoundSql 对象    BoundSql boundSql = ms.getBoundSql(parameterObject);    // 创建 CacheKey 对象    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);    // 查询    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);}@Overridepublic  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)            throws SQLException {    // 调用 MappedStatement#getCache() 方法,获得 Cache 对象,    //即当前 MappedStatement 对象的二级缓存。    Cache cache = ms.getCache();    if (cache != null) { // <2>         // 如果需要清空缓存,则进行清空        flushCacheIfRequired(ms);        //当 MappedStatement#isUseCache() 方法,返回 true 时,才使用二级缓存。默认开启。           //可通过@Options(useCache = false) 或  方式,    //开启需要清空缓存。    if (cache != null && ms.isFlushCacheRequired()) {        //调用 TransactionalCache#clear() 方法,清空缓存。        //注意,此时清空的仅仅,当前事务中查询数据产生的缓存。        //而真正的清空,在事务的提交时。这是为什么呢?        //还是因为二级缓存是跨 Session 共享缓存,在事务尚未结束时,不能对二级缓存做任何修改。        tcm.clear(cache);    }}

如何实现多个namespace的缓存共享?

关于多个namespace的缓存共享的问题,可以使用来解决。

比如:

cache-ref代表引用别名的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache。在关联的表比较少或者按照业务可以对表进行分组的时候可以使用。

「注意」:在这种情况下,多个mapper的操作都会引起缓存刷新,所以这里的缓存的意义已经不是很大了。

如果将第三方缓存作为二级缓存?

Mybatis除了自带的二级换以外,我们还可以通过是想Cache接口来自定义二级缓存。

添加依赖

              org.mybatis.caches         mybatis-redis         1.0.0-beta2    

redis基础配置项

    host=127.0.0.1    port=6379    connectionTimeOut=5000    soTimeout=5000    datebase=0

在我们的UserMapper.xml中添加

RedisCache类图,Cache就是Mybatis中缓存的顶层接口。

二级缓存应用场景

对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。

缓存查询顺序

先查二级缓存,不存在则坚持一级缓存是否关闭,没关闭,则再查一级缓存,还不存在,最后查询数据库。

二级缓存总结

二级缓存开启方式有两步:

第一步:在全局配置中添加配置

    

第二步,在Mapper中添加配置

二级换是默认开启的,但是针对每一个Mapper的二级缓存是需要手动开启的。

二级缓存的key和一级缓存的key是一样的。

每当执行insert、update、delete,flushCache=true时,二级缓存都会被清空。

我们可以继承第三方缓存来作为Mybatis的二级缓存。

到此,关于"总结MyBatis缓存结构"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0