Mybatis 一级缓存

缓存的概念

什么是缓存

存在于内存中的临时数据。

为什么使用缓存

减少和数据库的交互次数,提高执行效率。(因为查询数据库是一件很费时很费效率的事,还涉及一些硬盘等io操作,而缓存是存在内存中的,读取都很快,而且效率高)

什么样的数据能使用缓存,什么样的数据不能使用

适用于缓存

  • 经常查询并且不经常改变的。
  • 数据的正确与否对最终结果影响不大的。
    不适用于缓存
  • 经常改变的数据
  • 数据的正确与否对最终结果影响很大的。
  • 例如:商品的库存,银行的汇率,股市的牌价。

什么是一级缓存

mybatis 默认情况下只会开启一级缓存,也就是局部的 session 会话缓存。
如下图,每一个 session 会话都会有各自的缓存,这缓存是局部的,也就是所谓的一级缓存:
在这里插入图片描述

什么情况下会命中一级缓存

  • 相同的 sql 和 参数
  • 必须是在一个会话 Session当中
  • 必须是执行 相同的方法
  • 必须是相同的 namespace (同一个命名空间 -> 同一个mapper文件)
  • 不能够在查询之前执行 clearCache
  • 中间不能执行 任何 update ,delete ,insert (会将SqlSession中的数据全部清空)

Mybatis的一级缓存机制详解

一级缓存是SqlSession级别的缓存。我们都知道在操作数据库时需要构造 sqlSession对象,而在sqlSession对象中有一个数据结构(HashMap)用于存储缓存数据。在这里插入图片描述
从图上,我们可以看出,一级缓存区域是根据SqlSession为单位划分的。每次查询都会先从缓存区域找,如果找不到就会从数据库查询数据,然后将查询到的数据写入一级缓存中。Mybatis内部存储缓存使用的是一个HashMap对象,key为 hashCode + sqlId + sql 语句。而value值就是从查询出来映射生成的java对象。而为了保证缓存里面的数据肯定是准确数据避免脏读,每次我们进行数据修改后(增、删、改操作)就会执行commit操作,清空缓存区域。

一级缓存总结

一级缓存的生命周期和SqlSession对象的生命周期一致。所以缓存维护在SqlSession中的属性executor里。

一级缓存默认开启。可以通过修改配置项把一级缓存关掉。

清空一级缓存的方式有:

updateinsertdelete
flushCache="true"
commitrollback
LocalCacheScope.STATEMENT

二级缓存原理 ( mapper 级别)

范围是按照每个namepace缓存来存贮和维护,同一个namespace放到一个缓存对象中,当这个namaspace中执行了!
二级缓存的范围是 mapper 级别(mapper同一个命名空间,Namespace),mapper 以命名空间为单位创建缓存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。 key:MapperID+offset+limit+Sql+所有的入参

具体使用需要配置:

Mybatis 全局配置中启用二级缓存配置
在对应的 Mapper.xml 中配置 cache 节点
在对应的 select 查询节点中添加 useCache=true

只能在【只有单表操作】的表上使用缓存

不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。

避免使用二级缓存

为什么避免使用二级缓存?
在符合【Cache使用时的注意事项】的要求时,并没有什么危害。
其他情况就会有很多危害了。
针对一个表的某些操作不在他独立的namespace下进行。
例如在UserMapper.xml中有大多数针对user表的操作。但是在一个XXXMapper.xml中,还有针对user单表的操作。
这会导致user在两个命名空间下的数据不一致。如果在UserMapper.xml中做了刷新缓存的操作,在XXXMapper.xml中缓存仍然有效,如果有针对user的单表查询,使用缓存的结果可能会不正确。
更危险的情况是在XXXMapper.xml做了insert,update,delete操作时,会导致UserMapper.xml中的各种操作充满未知和风险。
有关这样单表的操作可能不常见。但是你也许想到了一种常见的情况。

多表操作一定不能使用缓存

为什么不能?
首先不管多表操作写到那个namespace下,都会存在某个表不在这个namespace下的情况。
例如两个表:role和user_role,如果我想查询出某个用户的全部角色role,就一定会涉及到多表的操作。

<select id="selectUserRoles" resultType="UserRoleVO">
    select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid}
</select>

复制
像上面这个查询,你会写到那个xml中呢??

不管是写到RoleMapper.xml还是UserRoleMapper.xml,或者是一个独立的XxxMapper.xml中。如果使用了二级缓存,都会导致上面这个查询结果可能不正确。
如果你正好修改了这个用户的角色,上面这个查询使用缓存的时候结果就是错的。
这点应该很容易理解。

在我看来,就以MyBatis目前的缓存方式来看是无解的。多表操作根本不能缓存。
如果你让他们都使用同一个namespace(通过)来避免脏数据,那就失去了缓存的意义。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值