目录
什么是查询缓存
mybatis
在查询数据的时候,会将数据存储起来,下次再次查询相同的数据,就不会再去查询数据库,而是直接从 缓存
中查询 ;
这样达到,减轻服务器压力,提高响应 ;
mybatis
提供 一级缓存 、二级缓存 ;
图解查询缓存
一级缓存
mybatis
在操作数据库的时候,会先创建sqlsession
,用sqlsession
去操作数据库 ;在每个
sqlsession
中,都有一个数据结构(hashmap
),用于存储缓存,在不同的sqlsession
之间,它们是相互不影响的 ;存储在这些
sqlsession
对象内部的缓存,就是一级缓存
;hashmap
的key
格式是 :查询到的对象的哈希码:satement 的 id:、、: 参数
;value
是查询到的对象 ;二级缓存
当多个不同的
sqlsession
对象,去使用同一个mapper
映射关系文件中的sql
语句,也会产生缓存,这个缓存是跨sqlsession
的,凡是使用同一个mapper
映射关系文件中的sql
语句的sqlsession
对象都是共享这个缓存的 ;缓存的底层也是
hashMap
;
一级缓存
原理
每次查询,会先去缓存中,检查要查询的数据,在缓存中有没有,如果有,则直接拿缓存中的数据 ;
如果缓存中没有的话,才去查询数据库,并将查询到的数据写入缓存 ;
如果执行过
commit
操作,则会清空全部缓存
,因为,commit
会对数据库数据进行修改,因此清空缓存,使得下次查询必须经过数据库,也就是保证数据库的缓存必须是最新的数据 ;图示
二级缓存
原理
当我们开启
二级缓存
的时候(默认就是开启的),查询数据的时候,是先去一级缓存
找,没有的话,再去二级缓存
中找,都没有的话,才会去查询数据库 ;当从数据库查询到信息以后,首先将查询到的数据存进
一级缓存
中,然后当sqlsession
关闭以后,sqlsession
中的一级缓存
,才会被写入二级缓存
;如果
sqlsession
执行了commit
操作了,也会清空二级缓存
;图示
注意:图中有2个地方被我画错了,复制第一个图 ,忘记修改了!!!我也不想重画了
sqlsession B
不应该是查询,应该是进行commit
操作 ;pojo
必须实现序列化
接口因为,我们的二级缓存的
hashmap
的 值 是查询到的pojo
对象,而我们有时候二级缓存
,并不是保存到 内存 中的,可能保存到 硬盘 上,这样就可以反序列化
;因此,使用
二级缓存
那么pojo
类必须实现序列化接口 ;注意点
二级缓存
,是按照mapper
文件的命名空间
划分的 ,只要命名空间
相同,则公用一份二级缓存
;最后只要
log
文件中出现命中率
,就代表二级缓存
开始使用了 ;命中率:
Cache Hit Ratio [xin.ijava.dao.UserMapper]: 0.3333333333333333
禁用二级缓存
select
标签中配置 useCache
属性,其默认值是 true
,将其值设为 false
,就会禁用 二级缓存
了
刷新缓存
mybatis
的 刷新缓存
,就是直接 清空缓存
,默认值是 true
,我们可以设置 commit
操作的属性 flushCache
的值为 false
让其不刷新缓存,一般不会这样做;
二级缓存应用场景
某信息,不经常变化,其用户对该信息实时性要求不高,这时候,可以使用二级缓存 ;
比如:电话账单
;
用户要想查询 前一天
、前一个月
的电话账单,电话账单一旦产生,基本就不会再变了,除非用户删除某条通话记录 ;
并且一般,对电话账单的实时性要求也不高,基本为 0
,营业厅给我们提供查什么时候的电话账单,我们就去查什么时候的;
比如,人家就提供了,查询前一天的电话账单,那么,我们想查今天的,只能等到明天再查今天的 ;
对于这样的信息,我们就可以使用 mybatis
的 二级缓存
了,并且在开启具体 mapper
的 二级缓存
的时候,配置刷新频率 flushInterval
;
刷新频率的时候根据需求而定,这里,人家提供查询前一天的数据,那么,我们的刷新频率,就设为 一天
;这样,当我们想查询昨天的电话账单的时候,也就第一次需要去查数据库,然后,今天的任意时候,再去查询,都是直接拿 二级缓存
;
等到明天的时候,我们设定的刷新频率 就会自动刷新缓存,因为,之前的缓存已经没用了,现在查询前一天的数据,应该是今天的数据 ;
二级缓存局限性
其实 mybatis
的二级缓存,应用的应该不广泛 ;它有很大的局限性 ;
比如,我们缓存中已经缓存了 10000
商品价格的记录,这样 ,当这一万条商品再被访问时,就不再去查询数据库了;
但是,只要这一万条里面的任意一条商品记录发生变化,那么 剩下的 9999
条记录,都会被一并刷新掉,这样,导致命中率很低;
也就是对 细粒度
的缓存很不友好,即想要具体到某一条改变了,只刷新改变的这一条记录的缓存,留下其他的没更改的数据缓存,mybatis
是做不到的,原因在于 mybatis
自己的缓存策略,只要其中一个 sqlsession
进行 commit
,即刷新缓存 ;
对于这样的问题,我们需要在 services
自己写逻辑进行完成,也就是所谓的 三级缓存
;