【深入MyBatis】二级缓存机制

前言

 MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。

一. MyBatis的缓存机制整体设计以及二级缓存的工作模式

14534869-09ad9ce0d78fd27f
MyBatis缓存机制示意图,图片来源https://blog.csdn.net/luanlouis/article/details/41408341

当开一个会话时,一个SqlSession对象会使用一个Executor对象来完成会话操作,MyBatis的二级缓存机制的关键就是对这个Executor对象做文章。

如果用户配置了"cacheEnabled=true",那么MyBatis在为SqlSession对象创建Executor对象时,会对Executor对象加上一个装饰者:

CachingExecutor,这时SqlSession使用CachingExecutor对象来完成操作请求。

CachingExecutor对于查询请求,会先判断该查询请求在Application级别的二级缓存中是否有缓存结果,如果有查询结果,则直接返回缓存结果;如果缓存中没有,再交给真正的Executor对象来完成查询操作,之后CachingExecutor会将真正Executor返回的查询结果放置到缓存中,然后在返回给用户.

MyBatis并不是简单地对整个Application就只有一个Cache缓存对象,它将缓存划分的更细,即是Mapper级别的,即每一个Mapper都可以拥有一个Cache对象,具体如下:

a.为每一个Mapper分配一个Cache缓存对象(使用<cache>节点配置);

b.多个Mapper共用一个Cache缓存对象(使用<cache-ref>节点配置);
    如果你想让多个Mapper公用一个Cache的话,你可以使用<cache-ref namespace="">节点,来指定你的这个Mapper使用到了哪一个Mapper的Cache缓存。

二. 二级缓存配置

要正确的使用二级缓存,需完成如下配置的。

1  在Mybatis的配置文件中开启二级缓存。

<setting name="cacheEnabled" value="true"/> 


2  在Mybatis的映射XML中配置cache或者 cache-ref 。

<cache/>


cache标签用于声明这个namespace使用二级缓存,并且可以自定义配置。可以配置的属性如下:

type:  cache使用的类型,默认是PerpetualCache,这在一级缓存中提到过。

eviction:  定义回收的策略,常见的有FIFO,LRU。

flushInterval:  配置一定时间自动刷新缓存,单位是毫秒

size:  最多缓存对象的个数

readOnly:  是否只读,若配置可读写,则需要对应的实体类能够序列化。

blocking:    若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。

cache-ref代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache。

<cache-ref  namespace="mapper.StudentMapper" />

三. 一级缓存和二级缓存的使用顺序

      请注意,如果你的MyBatis使用了二级缓存,并且你的Mapper和select语句也配置使用了二级缓存,那么在执行select查询的时候,MyBatis会先从二级缓存中取输入,其次才是一级缓存,即MyBatis查询数据的顺序是:

               二级缓存    ———>    一级缓存   ——>     数据库


四. 二级缓存实现的选择


MyBatis对二级缓存的设计非常灵活,它自己内部实现了一系列的Cache缓存实现类,并提供了各种缓存刷新策略如LRU,FIFO等等;另外,MyBatis还允许用户自定义Cache接口实现,用户是需要实现org.apache.ibatis.cache.Cache接口,然后将Cache实现类配置在<cache  type="">节点的type属性上即可;除此之外,MyBatis还支持跟第三方内存缓存库如Memecached的集成,总之,使用MyBatis的二级缓存有三个选择:

        1.MyBatis自身提供的缓存实现;

        2. 用户自定义的Cache接口实现;

        3.跟第三方内存缓存库的集成;

五.Cache实现类的介绍

Cache实现类的组合为Cache赋予了不同的能力。

SynchronizedCache: 同步Cache,实现比较简单,直接使用synchronized修饰方法。

LoggingCache: 日志功能,装饰类,用于记录缓存的命中率,如果开启了DEBUG模式,则会输出命中率日志。

SerializedCache: 序列化功能,将值序列化后存到缓存中。该功能用于缓存返回一份实例的Copy,用于保存线程安全。

LruCache:  采用了Lru算法的Cache实现,移除最近最少使用的key/value。

PerpetualCache: 作为为最基础的缓存类,底层实现比较简单,直接使用了HashMap。

六. 二级缓存注意的点

1.当sqlsession没有调用commit()或者close()方法时,二级缓存不会起到作用。

2.update操作会刷新该namespace下的二级缓存。

3.Mybatis的二级缓存不适应用于映射文件中存在多表查询的情况。
        由于Mybatis的二级缓存是基于namespace的,多表查询语句所在的namspace无法感应到其他namespace中的语句对多表查询中涉及的表进行了修改,引发脏数据问题。

4.为了解决第3点的问题,可以使用Cache ref,让ClassMapper引用StudenMapper命名空间,这样两个映射文件对应的Sql操作都使用的是同一块缓存了。不过这样做的后果是,缓存的粒度变粗了,多个Mapper namespace下的所有操作都会对缓存使用造成影响,

七.总结

Mybatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到Mapper级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。

Mybatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用的条件比较苛刻。

在分布式环境下,由于默认的Mybatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将Mybatis的Cache接口实现,有一定的开发成本,不如直接用Redis,Memcache实现业务上的缓存就好了。

最终的结论是Mybatis的缓存机制设计的不是很完善,在使用上容易引起脏数据问题,建议不要使用Mybatis缓存,在业务层面上使用其他机制实现需要的缓存功能,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值