java mybatis缓存机制_MyBatis缓存机制的设计与实现

本文主要讲解MyBatis非常棒的缓存机制的设计原理,给读者们介绍一下MyBatis的缓存机制的轮廓,然后会分别针对缓存机制中的方方面面展开讨论。

MyBatis将数据缓存设计成两级结构,分为一级缓存、二级缓存:

一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改)。

基于PerpetualCache的HashMap的本地缓存,一级缓存的作用域为sqlSession,当sqlSession被flush或close之后,当前sqlSession中的所有缓存都将被清空。

二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Application应用。

和一级缓存的机制相同,默认也是采用PerpetualCache的HashMap存储,但二级缓存的作用域是mapper(namespace)。

一级缓存

在举例子之前,我们先来看看一级缓存的工作原理:

我们在程序中第一次发起对用户id为1的用户信息进行查询时,会先去缓存中搜索是否有id为1的用户信息;如果没有,才会去数据库查询该用户的信息;得到用户信息后,将用户信息存储到一级缓存中;

第二次发起对用户id为1的查询,先去缓存中找是否存id为1的用户信息,缓存中有就会直接在缓存中取出相关数据;

如果sqlsession中执行了commit操作(增,删,改),sqlsession中的一级缓存会被清除,这样可以保证缓存中的信息时最新数据,避免脏读;

一级缓存测试

mybatis默认支持一级缓存,不需要在配置文件中设置;下面我们来看一级缓存的测试代码:

fc39629b955f37c94a0c9b035683a543.png

从执行结果中可以看出:

3b7b32dea2d532b110438be571e36085.png

第一次查询发出了一条sql语句,但是第二次查询并没有发出,因为第二次查询直接从一级缓存中取出数据;

但是,当我们将mybatis和Spring进行整合之后,事务将被控制在Service中:

c861ebd1b8672bcceae3c44feee9419c.png

一个Service中包括对很多mapper方法的调用,当我们执行两次Service的调用,查询相同用户的信息,就不会走一级缓存,因为第一个Service方法执行完毕之后,该方法的sqlSession已经被清空了,所以无法调用一级缓存;

二级缓存

ee1d371e5572af83ed44537730e26541.png和一级缓存的区别在于:二级缓存需要我们手动的开启;首先我们在开启二级缓存之前测试一下效果:

316a56b4a76b293767cff2c5c2a9ecc6.png

执行完上述代码之后,我们可以发现执行结果如下:

5290b2641bb78f2c451d12e427ef1c50.png

从上面的结果可以看出,我们没有开启之前,mybatis和数据库有两次交互的过程,也就是说默认情况下,mybatis的二级缓存是关闭的,需要我们手动设置。

开启二级缓存

(1)在核心配置文件SqlMapConfig.xml中加入以下内容(开启二级缓存总开关):

cacheEnabled设置为 true

012cdebc21f2c5b734f2d715f5e9c3d4.png

(2)在映射文件中,加入以下内容,开启二级缓存:

673fb21c993870c0b48102595314f9d0.png

实现序列化

由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。

如果该类存在父类,那么父类也要实现序列化。

43d0c7c1d9352878cb3766d252a8a5b8.png

禁用二级缓存

该statement中设置userCache=false可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存。

8ddb13409c72d417d1d0f0aca85a847f.png

刷新二级缓存

31d0261a7ce06b4e89936a837a8160e6.png

需要注意的是,使用二级缓存的时候,我们必须使用的是两个不同的session,并且只有在第一个缓存被提交的情况下才能使用二级缓存;

自定义缓存

EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

MyBatis定义了Cache接口方便我们进行自定义扩展。

步骤:

(1)导入ehcache包,以及整合包,日志包

23c9000de0d41957c33f8c48fd73d43e.png

(2)编写ehcache.xml配置文件(3)配置cache标签

c49560d1fa677c97152351c2f3b4ef62.png

若想在命名空间中共享相同的缓存配置和实例。可以使用 cache-ref 元素来引用另外一个缓存。

缓存相关属性

(1)eviction=“FIFO”:缓存回收策略:• 默认的是 LRU。

LRU – 最近最少使用的:移除最长时间不被使用的对象。

FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

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

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

(2)flushInterval:刷新间隔,单位毫秒

默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

(3)size:引用数目,正整数

代表缓存最多可以存储多少个对象,太大容易导致内存溢出

(4)readOnly:只读,true/false

true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。

false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

缓存相关设置

(1)全局setting的cacheEnable:

配置二级缓存的开关。一级缓存一直是打开的。

(2)select标签的useCache属性:

配置这个select是否使用二级缓存。一级缓存一直是使用的

(3)sql标签的flushCache属性:

增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。

查询默认flushCache=false。

(4)sqlSession.clearCache():

只是用来清除一级缓存。

(5)当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

总结

二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值