MyBatis笔记(五):MyBatis 缓存机制

       MyBatis 作为常用的 Java 数据库访问层ORM框架。Mybatis 也为我们提供缓存机制,用于减轻数据库压力,提高数据库性能。

在日常工作中,开发人员多数情况下是使用MyBatis的默认缓存配置,但是MyBatis缓存机制有一些不足之处,在使用中容易引起脏数据,形成一些潜在的隐患。

1.MyBatis 缓存分类

      MyBatis 提供了一级缓存二级缓存

  • 一级缓存:称为本地缓存,是 sqlSession 级别的缓存用于保存用户在一次会话过程中查询的结果,用户一次会话中只能使用一个sqlSession,一级缓存是自动开启的,不允许关闭(我们也可以自己关闭)。
  • 二级缓存:称为全局缓存,是 namespace 级别的缓存,是针对一个表的查询结果的存储,可以共享给所有针对这张表的查询的用户。也就是说对于nameSpace 级别的缓存,不同的 sqlsession 是可以共享这个缓存的。

2.二级缓存的由来

      一级缓存,只对当前会话有效。sqlSession1 和 sqlSession 2 是两个会话,如果 sqlSession2 已经修改了数据。sqlSession1 拿到的数据还会是之前缓存的旧数据,并不会拿到最新的数据,这就出现了脏数据的问题。现在我们就需要一个范围更广作用域的缓存,就引出了二级缓存这个概念!!!

3.缓存所在位置

       MyBatis 一级缓存存在于 Excutor(具体是在 BaseExecutor 类中),二级缓存是 namespace级别,作用域更大。所以 MyBatis 设计者将二级缓存存放在 Excutor 的包装类 CacheExecutor 中。

  一级缓存:
在这里插入图片描述
在这里插入图片描述
  二级缓存:

在这里插入图片描述
在这里插入图片描述

4.缓存如何打开

  • 一级缓存:默认是打开的。
    MyBatis 中的 <insert>、<update>、<delete> 这三个标签, flushCache 属性默认为 true,会自动清空缓存;|||||>>>select标签就不一样了, flushCache 属性默认为 false,不会自动清空缓存。不过我们可以根据实际情况,手动来修改该属性
  • 二级缓存:(大门)默认是打开的,但是这个打开和一级缓存的打开不一样。举个栗子:二级缓存相当于有两道门,默认只是打开了大门,每个小门的开关没打开,需要我们手动去配置。

大门: mybatis-config.xml 目录<settings>标签下

<settings>
	<!-- 2.2控制全局缓存(二级缓存)-->
	<setting name="cacheEnabled" value="true"/>
</settings>

小门: 每一个 mapper.xml 目录下,需要我们手动开启缓存。添加一个 标签,就说明当前 namespace 开启了二级缓存,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.springboot.dao.UserMapper">

    <!-- 声明这个 namespace 使用二级缓存 -->
    <cache/>

    <resultMap id="BaseResultMap" type="com.springboot.entity.User">
      ...省略...
    </resultMap>
	
	<select id="xxx" parameterType="xxx">
      ...省略..
	</select>

在这里插入图片描述
       你会发现 <cache> 标签有一个 readOnly 属性。该属性默认为 false。此属性的存在说明该缓存对象是可以被修改的。如果缓存对象被修改,那么被修改后缓存的对比之前的肯定就不是同一个对象,此时我们就需要返回该缓存对象的一个拷贝,这个拷贝就需要通过序列化来实现了。 所以我们缓存的这个对象,必须实现 Serializable 接口,否则会报错。

readOnly 为 ture 的话,则缓存对象无法修改,就是同一个对象,这样子效率会更高。
 
readOnly 为 false 的话,这样子更安全。

       二级缓存,我们也可以使用 Redis 等其他三方缓存组件,需要引入相关 Jar 包。配置信息如下:

 <cache type="org.mybatis.caches.redisCache"
		size="512"
		eviction="FIFO"
		flushInterval="60000"
		readOnly="true"/>

5.缓存如何关闭

  • 一级缓存:在 mybatis-config.xml 目录 <settings> 标签下
<settings>
	<!-- STATEMENT级别的缓存,使一级缓存,只针对当前执行的这一statement有效-->
	<setting name="localCacheScope" value="STATEMENT"/>
</settings>
  • 二级缓存:配置 cacheEnabled 属性为 false,或者 namespace 中不添加 <cache/>标签。
<settings>
	<!-- 2.2控制全局缓存(二级缓存)-->
	<setting name="cacheEnabled" value="false"/>
</settings>

       二级缓存意味着 namespace 下每个方法都会使用缓存。如果某个标签SQL不想使用二级缓存,我们可以为某个指定标签使用 "useCache = false"来关闭二级缓存。
在这里插入图片描述

6.缓存何时失效

  • 一级缓存:当前 sqlSession 会话期间,只要执行了 insert、delete、update 操作导致的数据被修改,一级缓存会失效
  • 二级缓存失效分两种情况: ①当前 nameSpace 下,每一个 sqlSession 会话的 insert、delete、update 操作都会导致数据被修改,二级缓存会失效;     ②如果长时间没有被修改,耳机缓存配置中,有一个 flushInterval 属性,到了该属性配置的指定时间,也会自动清空缓存

7.建议使用专门的缓存中间件

       二级缓存还是比较鸡肋,因为只要有其他的mapper(非当前namespace 的 mapper) 也调用了这个 namespace 所在 的 mapper.xml,二级缓存就会被清空。 二级缓存适用于一些查询的场合,诸如BI系统。

       其实 MyBatis 一级缓存、二级缓存还是比较鸡肋。MyBatis 在分布式环境下,由于默认的 Cache 实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将 MyBatis 的Cache 接口实现,有一定的开发成本,直接使用 Redis,Memcached 等分布式缓存可能成本更低,安全性也更高。


MyBatis 缓存机制,介绍到此为止

如果本文对你有所帮助,那就给我点个赞呗 ^ _ ^

End

发布了301 篇原创文章 · 获赞 66 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/lzb348110175/article/details/104577568