mybatis中的缓存

先简单介绍一下什么是一级缓存,二级缓存
在这里插入图片描述
MyBatis 中的缓存就是说 MyBatis 在执行一次SQL查询或者SQL更新之后,这条SQL语句并不会消失,而是被MyBatis 缓存起来,当再次执行相同SQL语句的时候,就会直接从缓存中进行提取,而不是再次执行SQL命令。
MyBatis中的缓存分为一级缓存和二级缓存,一级缓存又被称为 SqlSession 级别的缓存,二级缓存又被称为表级缓存。
SqlSession 是SqlSessionFactory会话工厂创建出来的一个会话的对象,这个SqlSession对象用于执行具体的SQL语句并返回给用户请求的结果。
SqlSession级别的缓存表示的就是每当执行一条SQL语句后,默认就会把该SQL语句缓存起来,也被称为会话缓存

MyBatis中的一级缓存

一级缓存是 SqlSession级别 的缓存。在操作数据库时需要构造 sqlSession 对象,在sqlSession对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

具体见:Mybatis一级缓存

在代码中,可以理解为一个mapper就是一个sqlSession
当一次查询操作发生时,首先会根据key(mapper的包名+类名+sql名称+limit+offset+sql语句+sql参数)去缓存中查询,如果没有查到的话就会去数据库中查询结果并根据上面的key存入缓存,那么第二次相同条件的查询就会先去缓存中查询,命中缓存的话就会直接返回
但是如果第二次查询的条件有一个条件有变化,就会导致key对应不上。此时就会重新去数据库中查询并在缓存中新增
当两次查询之间有update,delete,insert操作时,sqlSession会自动在操作前清空该sqlSession中的所有缓存再执行对应的操作。

MyBatis中的二级缓存

参考:MyBatis中的二级缓存
MyBatis 一级缓存最大的共享范围就是一个SqlSession内部,那么如果多个 SqlSession 需要共享缓存,则需要开启二级缓存,开启二级缓存后,会使用 CachingExecutor 装饰 Executor,进入一级缓存的查询流程前,先在CachingExecutor 进行二级缓存的查询,具体的工作流程如下所示
在这里插入图片描述
当二级缓存开启后,同一个命名空间(namespace) 所有的操作语句,都影响着一个共同的 cache,也就是二级缓存被多个 SqlSession 共享,是一个全局的变量。当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。

二级缓存的相关配置

二级缓存默认是不开启的,需要手动开启二级缓存,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。原因是:在执行过程中,因为二级缓存是可跨线程的,所以可能导致两个线程拿到同一个对象。如果不进行序列化,那么如果线程1修改了缓存中的数据,线程2去获取缓存中的数据,在线程2获取数据后,线程1进行回滚,从而导致了线程2的脏读。为了解决这个问题,所以必须把这个对象序列化,这样两个线程拿到的对象是一样的,但是序列化的ID是不一样的,这样就可以很好的解决这个问题
开启二级缓存的配置很简单,通过在 MyBatis 配置文件中配置即可

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

在配置文件中开启后,还需要在具体的mapper文件里进行配置,有两种配置方式:
1.通过xml来实现
 在xml配置文件中加入 标签并设置 cache 标签的属性
 cache 标签的属性如下:
  eviction: 缓存回收策略,有这几种回收策略
   LRU - 最近最少回收,移除最长时间不被使用的对象(默认)
   FIFO - 先进先出,按照缓存进入的顺序来移除它们
   SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
   WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
  flushinterval 缓存刷新间隔,缓存多长时间刷新一次,默认不清空,设置一个毫秒值
  readOnly: 是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修改
  size : 缓存存放多少个元素
  type: 指定自定义缓存的全类名(实现Cache接口即可)
  blocking:若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。
2.通过@CacheNamespace注解来实现
@CacheNamespace注解的属性如下:
 implementation:设置缓存的默认实现,默认是PerpetualCache.class
 evicition:默认溢出淘汰策略,默认LruCache.class
 flushInterval:缓存有效期,默认0 即用不失效
 size:缓存容量
 readWrite:是否要序列化和反序列化
 blocking:设置是否需要放置缓存穿透
 properties:为缓存设置属性(为implementation中的类设置属性)

需要注意的是,xml和注解如果都用上了的话,需要用@CacheNamespaceRef指定引用的缓存空间

二级缓存的生命周期

二级缓存和一级缓存的生命周期其实差不多,都是在查询的时候先去查缓存,如果没有的话再去查数据库并将结果存入缓存(这里需要注意的是,只有这个查询的sql被提交之后,才会把查询结果写入缓存),在执行更新操作的时候先将缓存清除,然后更新,区别就是具体的存入,取出等方法是可以由自己实现的(具体的Cache实现类),具体的配置也可以进行自定义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值