1、mybatis缓存机制

mybatis为减轻数据库压力,提高数据库性能。提供了两级缓存机制:

  1. 一级缓存
    SqlSession级别的缓存,缓存的数据只在SqlSession内有效。
    一级缓存mybatis已近为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。
    一级缓存是sqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个基于 PerpetualCache的HashMap本地缓存数据结构,用于缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互不影响的。

  2. 二级缓存
    mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的。
    二级缓存需要我们手动开启。
    二级缓存(全局级别) 是mapper级别的缓存,多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。

2、一级缓存

一级缓存原理:

  1. 第一次查询用户id为1的用户信息,先去缓存中查询是否有id为1的用户信息,如果没有,从数据库中查询用户信息。得到用户信息后再将用户信息储存到一级缓存中。
  2. 如果sqlSession去执行commit 操作(插入、更新、删除),就会清空sqlSession中的一级缓存,保证缓存中始终保存的是最新的信息,避免脏读。
  3. 第二次查询用户id为1的用户信息,先去缓存中查询是否有id为1的用户信息,如缓存中有,直接从缓存中获取。
  4. 注意:两次查询须在同一个sqlsession中完成,否则将不会走mybatis的一级缓存。在mybatis与spring进行整合开发时,事务控制在service中进行,重复调用两次servcie将不会走一级缓存,因为在第二次调用时session方法结束,SqlSession就关闭了

注意事项:

  1. mybatis默认是开启一级缓存,不需要配置
  2. 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中存的数据永远和数据库中一致,避免出现脏读
  3. 一个SqlSession结束后那么它里面的一级缓存也就不存在了。
  4. mybatis的缓存是基于 [ namespace:sql语句:参数 ] 来进行缓存的。意思就是,SqlSession的HashMap存储缓存数据时,是使用 [ namespace:sql:参数 ] 作为key,查询返回的语句作为value保存的。

3、二级缓存

二级缓存与一级缓存原理相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper ( Namespace ),并且可自定义存储源,如 Ehcache。作用域为 namespance 是指对该 namespance 对应的配置文件中所有的 select 操作结果都缓存,这样不同线程之间就可以共用二级缓存。

二级缓存是基于映射文件的缓存(namespace),缓存范围比一级缓存更大,不同的SQLSession可以访问二级缓存的内容。哪些数据放入二级缓存需要自己指定

二级缓存可以设置返回的缓存对象策略:

  1. readOnly=“true”(只读):MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户 。不安全,速度快。
  2. readOnly=“false”(读写,默认):MyBatis 觉得获取的数据可能会被修改,MyBatis 会利用序列化或反序列化的技术克隆一份新的数据。安全,速度相对慢。

二级缓存的具体流程:

  1. 当一个sqlseesion执行了一次select后,并关闭此session的时候,就会将查询结果存储到二级缓存中
  2. 当另一个sqlsession执行相同select时,首先会查询二级缓存,二级缓存中无对应数据,再去查询一级缓存,一级缓存中也没有,最后去数据库查找,从而减少了数据库压力提高了性能

注意事项:

  1. 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前mapper缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
  2. mybatis的缓存是基于[ namespace:sql语句:参数 ]来进行缓存的,意思就是,SqlSession的HashMap存储缓存数据时,是使用[ namespace:sql:参数 ]作为key,查询返回的语句作为value保存的。
  3. 开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作

4、开启mybatis二级缓存

4.1.1、通过application.yml配置二级缓存开启
# mybatis相关配置
mybatis:
  configuration:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      #开启MyBatis的二级缓存
      cache-enabled: true
4.1.2、通过MyBatis配置文件开启二级缓存【在MyBatis-config.xml 文件中添加如下代码】
<setting name="cacheEnabled" value="true"/>
4.2、在 xxxMapper.xml 文件中添加
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"/>
4.3、属性解释

eviction:缓存的回收策略,默认的是 LRU。

  • LRU - 最近最少使用,移除最长时间不被使用的对象。
  • FIFO - 先进先出,按对象进入缓存的顺序来移除它们。
  • SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK - 弱引用,更积极地移除基于垃圾收集器和弱引用规则的对象。

flushInterval:缓存刷新间隔。缓存多长时间清空一次,默认不清空,设置一个毫秒值。

readOnly:是否只读。

  • true(只读):
  • false(读写,默认)

size:缓存存放多少个元素。

type:指定自定义缓存的全类名(实现 Cache 接口即可)。PS:要使用二级缓存,对应的 POJO 必须实现序列化接口 。

4.4、是否使用一级缓存

如果一条句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为 false,如:

<select id="selectUserById" resultMap="map" useCache="false">

二级缓存默认会在 insert、update、delete 操作后刷新缓存。但可以手动配置不更新缓存

<update id="updateUserById" parameterType="User" flushCache="false">
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐