暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

mybatis一二级缓存详解

学习王国 2021-07-20
224

          今天上班的时候碰到一个比较诡异的问题,在同一个事务中先根据某条数据的唯一字段查询,查询的结果为空,然后就插入这条数据,最后再根据这个这段去查,按理说返回的结果应该是有数据的,但是结果却是null,究其原因发现是因为mybatis的一级缓存造成的,我们的数据库持久层框架整合了mybatis和jpa,我们用mybatis来查这条数据,用jpa来插入这条数据,最终造成了同一事物中数据在插入后查询不到的问题,最后的解决方案是关掉mybatis的一级缓存

        基于此我详细的去了解了一下mybatis的一二级缓存,首先我们先从一级缓存说起,如下图:


        如图所示mybatis的一级缓存是和sqlSession绑定的,也就是属于一次对话,这里我们从源码的角度再来理解一下


       localCache本质上是个map,这里为什么用一个map这么简单是因为它属于一个会话级别的缓存,随着会话的关闭而消失,所以一个会话里能存入的缓存量也相对较小,在mybatis中它也是默认开启的,可以通过配置关闭掉一级缓存,而我在工作中遇到的那个是因为我先用mybatis按条件查询,查不到以后就通过jpa去插入(整合了两种持久层框架),之后再用mybatis去查,在jpa进行插入的过程中没有清理掉之前mybatis查询的一级缓存,如果是mybatis的插入会走update清理掉一级缓存,如图:

      


       接着我们再来看看二级缓存,它是属于mapper级别的缓存


           什么叫mapper级别的缓存呢,比如说在你用mapper去操作的时候,每一次调用他都会去开启一个SqlSession会话,从上图中也可以看到,它会先去查二级缓存,查不到再去查一级缓存,二级缓存默认是关闭的,下图是如何开启二级缓存的流程:

 

        当然你还可以进行按需进行更细化的配置,比如针对特殊查询关闭掉二级缓存


        最后我们来看一下整个一二级缓存的源码调用路径,首先它会去查一级缓存,一级缓存先要配置cacheEnabled为true,还可以指定它缓存的淘汰策略,如图:



         配置开启一级缓存的话,就将sql执行器转换成缓存caching执行器,运用的是装饰器模式,我们再进去看看它的query方法


        这里其实我们也可以想想,为啥二级缓存一个map,而一级缓存搞的那么复杂,其实归根到底就是他们两个缓存的数据量不一样决定的,我们接着往后面看,delegate.query已经很直白了,就是说装饰者对象调用,我们点进query方法看看发现来到了我们最开始的那张图


总结:mybatis的一级缓存属于mapper级别的缓存,二级缓存是session会话级别的缓存,这和计算机的一级高速缓存和二级高速缓存有所区别,主要表现在数据量的大小差异,计算机的一级高速缓存要比二级高速缓存要小,且速度更快,另外虽然缓存可以解决稍微提高性能,减少对mysql的访问,但是也容易影响到业务,所以在开启的时候要多方面考虑

文章转载自学习王国,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论