mybatis缓存机制

Mybatis提供一级缓存,二级缓存和自定义缓存:


一级缓存是SqlSession级别,其最大的共享范围就是一个SqlSession内部,如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。默认情况下,mybatis 的一级缓存是开启的。

二级缓存是mapper级别的缓存,对于mapper级别的缓存不同的sqlsession是可以共享的。

一.一级缓存

 如下图所示,MyBatis会在一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在缓存中,就直接从缓存中取出,然后返回给用户,从而减少资源浪费;否则,从数据库读取数据,将查询结果存入缓存并返回给用户,session关闭,缓存将被清空。


Mybatis一级缓存默认开启,无需配置。

测试案例1

运行结果:

可以看到同一个sqlSession两次查询只是发出了一条sql语句,第二次查询是从缓存中读取。

第二个newSqlSession查询的时候也是发出了sql语句,因为缓存已经被清空了,由此可见mybatis一级缓存的sqlsession是不共享的

测试案例2

测试结果:

第一步 查询发起sql语句,并将查询结果放入缓存,

第二步对该语句进行更新操作,缓存将被清空

第三步再次查询信息,该语句又发起一次sql语句。

二.二级缓存

二级缓存可以使用MyBatis自己定义的二级缓存实现;也可以通过实现Cache接口自定义缓存(使用第三方内存缓存库,如redis)。

1.   MyBatis自定义的二级缓存工作机制:


a).特点:即松散的Cache缓存管理和维护

一个Mapper中定义的增删改查操作只能影响到自己关联的Cache对象,如图所示namespace1产生的缓存只会被放置到相应关联的Cache1中,即Mappernamespace2,namespace3,namespace4 中的CRUD的语句不会影响到Cache1。

b).Mapper之间的缓存关系比较松散,相互关联的程度比较弱

如果将AMapper和BMapper共用一个Cache对象,当BMapper执行更新操作时,可以清空对应Cache中的所有的缓存数据,使缓存使用效率变的很低!AMapper和BMapper的任意的更新操作都会将共用的Cache清空,会频繁地清空Cache,导致Cache实际的命中率和使用率就会变得很低,这种策略实际情况下是不可取的。

相关配置:

SqlSessionFactory层面上的二级缓存是不开启的,二级缓存开启需要配置。

1.使用注解@CacheNamespace方式配置,不写type就使用mybatis默认的缓存,也可以去实现 Cache 接口来自定义缓存
   
@CacheNamespace注解详情:
Implementation: 实现缓存功能的类
PerpetualCache这个类是mybatis默认实现二级缓存功能的类
Eviction:缓存回收策略(可选值有"LRU"、"FIFO"、"SOFT"、"WEAK",默认值是LRU
LruCache:最近最少使用,移除最长时间不被使用的对象.

FIFO:先进先出,按对象进入缓存的顺序来移除

SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象

WEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象

flushInterval: 指缓存过期时间,单位为毫秒.
默认为0,即只要容量足够,永不过期
Size:指缓存多少个对象
默认值为1024
readWrite:可读/可写
默认为true
Bloking:锁
默认为false
2.对于MyBatis自带二级缓存,实体类可以不用实现序列化接口。

测试案例1:

测试结果:

创建两个sqlSession对象,

第一次查询发出sql语句,将查询结果翻入缓存中,关闭第一个sqlsession,用第二个sqlsession发起查询,数据是从缓存中读取的,由此可见mybatis二级缓存sqlSession之间是共享的.

测试案例2:

测试结果:

第一步sqlSessionOne进行sql查询操作,将查询结果放入缓存中

第二步sqlSessionTwo执行更新操作,缓存将被清空

第三步sqlSessionThree进行查询操作,重新发起sql查询。

执行更新操作,二级缓存数据将被清空

三.自定义缓存Redis

为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存,通过重写Cache接口中的方法,将mybatis中默认的缓存空间映射到redis空间中。

相关配置:

自定义类MybatisCache通过重写Cache接口中的方法,自定义缓存.

 


flashInterval:指缓存过期时间,单位为毫秒,60000即为60秒 

 2.自定义缓存redis有时会将数据缓存到硬盘上需要实现 Serializable 序列化接口


开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要再取这个缓存的话,就需要反序列化了。所以mybatis中的pojo需要实现Serializable接口。

测试案例1:

测试结果:

第一步sqlSessionOne进行sql查询操作,将查询结果放入redis缓存中

 

Redis查看结果,数据已被序列化:

第二步sqlSessionTwo执行更新操作,缓存将被清空

Redis查看结果:

第三步sqlSessionThree进行查询操作,重新发起sql查询。

执行更新操作,二级缓存redis数据将被清空

打开Redis查看结果:

 

禁用二级缓存使用@Options注解,将useCache属性设置为false

options有个timeout

mybatis如果不指定,默认超时时间是不做限制的,默认值为-1.

以秒为单位,当超出了设置的超时时间时,会抛出SQLTimeoutException

#为什么不用mybatis原生态缓存?

因为mybatis原生态缓存有局限性,mybaits的二级缓存区域是以mapper为单位划分,比如某列表使用了join链接查询,当对其中一个表(做了增删改操作)数据发生变动时,会将cache全部清空,从而倒导致cache实际命中率和使用率变低,这种策略不符合我们的业务场景。

测试案例1,使用mybatis原生态缓存:

测试结果,多次修改表1,表2数据始终使用sql查询:

测试案例2,使用redis缓存:

需注释掉cache接口的清空缓存clear()方法,因为每次增删改都清空缓存会消耗缓存的内存资源

测试结果:

1.     第一次执行联表查询将数据放入到缓存中,后对表1进行更新操作,对表2执行sql查询,发现数据是从缓存中读取。


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Snail_Echo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值