mybatis的一二级缓存

MyBatis 给我们提供了一级缓存和二级缓存机制来提高查询效率和减少数据库交互次数,一级缓存主要用于单次数据库会话内的查询优化,而二级缓存则着眼于整个应用层面的数据复用。

一级缓存(Local Cache)

  1. 特点

    • 一级缓存是 SqlSession 级别的缓存,也称为本地缓存,每个 SqlSession 内部都有一个本地缓存。
    • 在同一个 SqlSession 生命周期内有效,即在打开一个 SqlSession 到关闭 SqlSession 这个过程中,执行相同 SQL 语句时,MyBatis 会先查找一级缓存中是否有对应结果,如果有就直接返回,不再查询数据库。
    • 当在同一个 SqlSession 内执行了任何修改操作(增删改),会立即清空一级缓存,以保证数据一致性。
    • 当 SqlSession 关闭时,一级缓存会被清空。
  2. 工作原理

    • MyBatis 使用一个 HashMap 来存储一级缓存,键值是基于 SQL 语句(包括参数)生成的一个唯一标识。
    • 第一次查询时,结果会被存入缓存;第二次执行相同的查询时,若缓存未失效,则直接从缓存中获取结果。

二级缓存(Second Level Cache)

  1. 特点

    • 二级缓存是全局性的,跨越了 SqlSession 的边界,不同的多个 SqlSession 可以共享相同的二级缓存区域。
    • 二级缓存需要在全局配置文件中开启,并且在具体的 Mapper 映射文件中通过 <cache> 标签进行详细配置才能生效。
    • 二级缓存通常基于 Mapper 级别进行管理,意味着只有同一个 Mapper 下的查询结果才会被缓存在一起。
    • 当不同 SqlSession 执行相同的 SQL 查询时,如果开启了二级缓存并且相关数据存在于缓存中,则可以从二级缓存中获取结果,从而避免再次查询数据库。
  2. 工作原理

    • 当一个 SqlSession 关闭后,其一级缓存中的数据可能会被移至二级缓存中(如果配置了二级缓存)。
    • 新的 SqlSession 在执行查询时,如果查询条件与已经存在于二级缓存中的数据匹配,MyBatis 会直接从二级缓存中获取数据,避免直接访问数据库。
    • 二级缓存可以配置各种策略,比如缓存过期时间、缓存淘汰算法(LRU、FIFO 等)、是否支持读写等。
  3. 注意事项

    • 二级缓存带来的潜在问题是数据一致性,尤其在多线程或多用户环境下,当数据库发生更新时,如果没有恰当的缓存同步机制,可能会导致脏读问题。
    • 若要使用二级缓存,需要确保被缓存的相关的实体类(POJO)实现了 Serializable 接口,以便在必要时进行序列化和反序列化。
    • 在执行增删改操作时,MyBatis 并不会自动更新二级缓存,开发人员需要手动处理缓存同步,可通过设置 <cache> 标签的 flushInterval 属性定期刷新缓存,或者在插入、更新或删除操作后调用 clearCache() 清除缓存。
  4. 开启二级缓存:
    • ​​​​在 MyBatis 的全局配置文件(mybatis-config.xml)中,默认情况下 cacheEnabled 属性值为 true,表示全局缓存开启。
    • 但在实际应用中,还需要在具体 Mapper 的 XML 映射文件或者对应的 Mapper 接口中显式地声明使用二级缓存,即在 <mapper> 标签内添加 <cache> 子标签来配置二级缓存。
    • 可以配置二级缓存的各种属性,如缓存大小、缓存的并发策略(read-write 或 read-only)、缓存的回收策略(LRU、FIFO 等)以及缓存的存活时间等。

​​​​​​​        全局配置开启二级缓存: 首先,你需要在 MyBatis 的全局配置文件(通常是 mybatis-config.xml)中开启二级缓存。在 Spring Boot 中,你可以在 resources 目录下创建这个文件,或者在 application.properties 或 application.yml 中配置 MyBatis 的配置路径。在 mybatis-config.xml 文件中设置 cache-enabled 属性为 true

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><settings><!-- 开启二级缓存 --><setting name="cacheEnabled" value="true"/><!-- 其他配置项... --></settings>
</configuration>

Mapper 中启用二级缓存: 仅仅开启全局的二级缓存还不够,你还需要在各个需要用到二级缓存的 Mapper 映射文件中启用缓存。在对应的 Mapper XML 文件中加入 <cache> 标签:

<?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.example.mapper.YourMapper"><!-- 启用二级缓存 --><cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/><!-- 其他SQL映射... -->
</mapper>

在 <cache> 标签内,你可以配置二级缓存的各种属性,例如驱逐策略(eviction)、刷新间隔(flushInterval)、缓存大小(size)以及是否只读(readOnly)等。

二级缓存属性:
  1. enabled

    • 默认值:true (如果在 <cache> 标签内未指定,则该 Mapper 是否启用二级缓存)
    • 说明:决定是否启用该 Mapper 对应的二级缓存。
  2. eviction

    • 默认值:LRU(Least Recently Used 最近最少使用)
    • 说明:缓存对象的驱逐策略,用于决定当缓存达到最大容量时如何剔除旧的条目。可选值有:
      • LRU - 最近最少使用的对象将被剔除。
      • FIFO - 先进先出(First In First Out)策略,最早放入缓存的对象将被首先剔除。
      • SOFT - 软引用策略,依据 JVM 的垃圾回收机制决定何时剔除。
      • WEAK - 弱引用策略,类似于软引用,但在 GC 时更易被回收。
  3. flushInterval

    • 默认值:0(不自动刷新)
    • 说明:缓存刷新间隔,单位是毫秒。如果设置了非零值,那么缓存将在指定时间间隔后自动刷新,这意味着所有缓存数据都会失效,下次查询时会重新从数据库加载。
  4. size

    • 默认值:无限制
    • 说明:缓存的最大容量,超过这个数量的对象将触发驱逐策略。
  5. readOnly

    • 默认值:false
    • 说明:指示缓存是否只读。如果设置为 true,那么当对象被从缓存中读取时,MyBatis 不会跟踪其状态变化,也不会在更新操作后清空缓存。这样可以提高性能,但也有可能导致缓存数据与数据库数据不一致的问题。如果设置为 false,则会对缓存对象的状态变化进行跟踪,以确保缓存数据与数据库保持一致。
  6. blockFlush

    • 默认值:取决于具体实现
    • 说明:是否阻塞刷新操作,某些缓存实现可能会支持异步刷新,此属性可控制是否等待刷新完成后再继续。
  7. blockRead

    • 默认值:取决于具体实现
    • 说明:是否在读取操作时阻塞,当缓存正在刷新时,是否等待刷新完成后再读取。
  8. serialize

    • 默认值:true(在某些实现中可能是必需的)
    • 说明:决定是否序列化缓存对象。由于二级缓存通常涉及跨线程和跨进程共享数据,因此存储的对象必须是可序列化的。
  9. 还可以通过 <cache> 标签中的 type 属性指定具体的缓存实现类,以使用自定义的缓存插件或第三方比如Redis缓存库。
举个例子:

可以根据需求创建个mapper,比如<cache> 标签开启了 EmployeeMapper 的二级缓存,并指定了缓存的驱逐策略(这里是 LRU)、缓存大小以及是否只读:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.EmployeeMapper"><!-- 启用二级缓存 --><cache eviction="LRU" size="1024" readOnly="false"/><!-- 查询映射 --><select id="selectEmployeeById" resultType="com.example.model.Employee" useCache="true">SELECT * FROM employee WHERE id = #{id}</select><!-- 更新、插入、删除映射也要包含进来,因为它们会影响缓存 --><!-- ... -->
</mapper>

然后这样使用:

// 创建两个 SqlSession 实例
SqlSession session1 = sqlSessionFactory.openSession();
SqlSession session2 = sqlSessionFactory.openSession();try {// 第一次查询EmployeeMapper mapper1 = session1.getMapper(EmployeeMapper.class);Employee emp1 = mapper1.selectEmployeeById(1);// 输出第一次查询结果// 第二次查询,假设使用了另一个 SqlSessionEmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);Employee emp2 = mapper2.selectEmployeeById(1);// 因为二级缓存已启用,emp1 和 emp2 应该指向同一份缓存数据// 更新操作emp1.setName("New Name");mapper1.updateEmployee(emp1);session1.commit();  // 更新提交后,二级缓存中的对应数据应当失效// 手动清空受影响的二级缓存,然而,这种方法并不精细,因为它清空了整个 Mapper 的二级缓存,而不是仅针对被修改的特定记录。sqlSession.clearCache();// 再次查询,此时应从数据库获取最新的数据Employee emp3 = mapper2.selectEmployeeById(1);// emp3 应该反映了数据库中更新后的名称
} finally {session1.close();session2.close();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/1829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java Collections类、Stream流

Collections类 Java中的Collections类是一个功能丰富的工具类&#xff0c;它提供了一系列静态方法来操作和处理集合。以下是一些主要的功能&#xff1a; 创建集合&#xff1a;可以使用Collections类创建空集合、单元素集合以及不可变集合等。这为集合的初始化提供了便利。排序…

3i平台体验性能加持,13600KF+B760M+撼与科技A770 TITAN装机体验

在2022年&#xff0c;intel重启显卡线&#xff0c;带来了多款性价比十分不错的显卡。而近段时间&#xff0c;又有传言说intel第二代产品e即将面世&#xff0c;甚至已经有数款Battlemage GPU曝光&#xff0c;让不少intel忠实粉丝直呼期待&#xff0c;或许在今年年底&#xff0c;…

mysql面试题八(SQL语句)

目录 1.SQL 基本组成部分 常用操作示例 创建表 插入数据 查询数据 更新数据 删除数据 创建索引 授予用户权限 2.常见的聚合查询 1. 计数&#xff08;COUNT&#xff09; 2. 求和&#xff08;SUM&#xff09; 3. 平均值&#xff08;AVG&#xff09; 4. 最大值&…

卸载jenkins和docker

要卸载Docker中部署的Jenkins以及相关的容器和数据卷&#xff0c;您可以按照以下步骤操作&#xff1a; 卸载Jenkins容器及关联数据卷 停止并删除Jenkins容器&#xff1a; 使用Docker命令找到Jenkins容器的ID&#xff08;如果您还不知道&#xff09;&#xff0c;然后停止并删除…

在stm32中,所需的库函数有那些

使用库函数中封装的函数来访问外设可以使得stm32开发更加方便&#xff0c;省去了查寄存器位操作&#xff0c;只用查库函数就可以了 但是使用库函数时要记住真正的其本质是获取寄存器的地址然后设置其中的位 库函数一般添加到自己创建的Lib文件夹中 库函数实际上分成了两块&…

vue e.target.currentSrc 获取图片图片里包含中文名字出现乱码

<div v-html"info.brief" class"content" click"judgeImg($event)"></div> //判断是否为图片并提取当前图片地址judgeImg(e){ let currentSrc decodeURIComponent(e.target.currentSrc) }, 在 Vue 中&#xff0c;当你从 e…

Opencv | 图像卷积与形态学变换操作

这里写目录标题 一. 滤波 / 卷积操作1. 平滑均值滤波/卷积2. 平滑中值滤波/卷积3. 平滑高斯滤波/卷积3.1 关注区域3.2 分解特性 二. 形态学变换1. 常用核2. cv.erode ( ) 腐蚀操作3. cv.dilate ( ) 膨胀操作4. Open 操作5. Close 操作6. Morphological Gradient 形态梯度操作7.…

设计模式之创建型模式---工厂模式

文章目录 工厂模式概述简单工厂简单工厂的代码实现简单工厂的使用简单工厂应用场景 工厂方法工厂方法模式的代码实现工厂方法的使用工厂方法应用场景 抽象工厂抽象工厂模式代码实现抽象工厂的使用方法抽象工厂模式的应用场景 总结 工厂模式概述 工厂模式从名字就能看出&#x…

查看文件的权限和实际类型

该文件确实存在于指定的位置。可以使用 ls 命令来检查文件是否存在&#xff0c;以及确认文件路径是否正确。 ls -l xxx.xx权限问题: 确保你有权限读取该文件。如果该文件位于受限制的目录中&#xff0c;可能需要使用 sudo 或其他管理员权限来运行命令。 文件格式不正确: 如果…

JS走马灯小功能制作

HTML代码&#xff1a; <div id"contain"><div id"content"> 作文&#xff0c;怎样才能写好&#xff1f;作文&#xff0c;好于勤读&#xff0c;作文&#xff0c;优于真情。作文一词&#xff0c;汇于欲要看究竟&#xff0c;处处细留心。作文于此…

损失函数汇总

kl 在多分类问题中&#xff0c;KL&#xff08;Kullback-Leibler&#xff09;损失通常用于衡量模型预测的概率分布与真实标签的概率分布之间的差异。在多分类任务中&#xff0c;通常使用交叉熵损失&#xff08;Cross Entropy Loss&#xff09;作为主要的损失函数&#xff0c;但…

Threejs绘制传送带

接下来会做一个MES场景下的数字孪生&#xff0c;所以开始做车间相关的模型&#xff0c;不过还是尽量少用建模&#xff0c;纯代码实现&#xff0c;因为一方面可以动态使用&#xff0c;可以调节长度和宽度等&#xff0c; 下面这节就做一个简单的传送带&#xff0c;这是所有车间都…

c++计算DNA探针的熔解温度

DNA探针的熔解温度(Tm)是指DNA双链在解离过程中的温度,可以用来估计DNA探针与靶序列的结合强度。 DNA探针富集实验中使用的盐浓度通常是在高盐条件下进行的,以帮助DNA与探针结合并提高富集效率。一般来说,盐浓度在0.5 M到1 M之间是常见的范围,但具体的盐浓度会根据实验的…

基础SQL DML-插入语句

插入语句前&#xff0c;我们先创建一个表。表的创建在DDL语句里面涉及&#xff0c;可以参考&#xff1a;小赖同学吖-CSDN博客 我们创建一个员工表进行数据的插入操作 插入&#xff08;添加&#xff09;语句的语法 给员工表添加一条记录 给员工表添加多条记录 也可以通过下面的方…

年薪5.8万美元|临床医生赴美国康奈尔大学从事博士后研究

作为临床医学8年制的博士毕业生&#xff0c;A医生希望能到国外从事一段时间的博士后&#xff0c;以强化基础科研训练&#xff0c;弥补职业发展的短板。最终我们为其申请到康奈尔大学Weill Cornell医学院的博士后职位&#xff0c;年薪为5.8万美元。 A医生背景&#xff1a; 申请…

C语言项目实践——贪吃蛇

引言&#xff1a;本篇博客中&#xff0c;我将会使用结构体&#xff0c;链表&#xff0c;WIN32 API等一系列知识完成C语言项目——贪吃蛇的实现。在观看此篇博客之前&#xff0c;请将这些知识所熟悉&#xff0c;不然可能会造成理解困难。 更多有关C语言的知识详解可前往个人主页…

【C++】explicit关键字详解(explicit关键字是什么? 为什么需要explicit关键字? 如何使用explicit 关键字)

目录 一、前言 二、explicit关键字是什么&#xff1f; 三、构造函数还具有类型转换的作用 &#x1f34e;单参构造函数 ✨引出 explicit 关键字 &#x1f34d;多参构造函数 ✨为什么需要explicit关键字&#xff1f; ✨怎么使用explicit关键字&#xff1f; 四、总结 五…

CentOS 7离线升级OpenSSH至9.1p1操作过程及遇上的问题

在文章顶部下载适用于CentOS7的OpenSSH 9.1p1 rpm包&#xff0c;包含了服务器和客户端。 默认全部以root用户权限执行命令。 简单版 懒得看的话&#xff0c;复制以下4行命令执行即可。 tar -zxvf centos7-openssh-9.1p1.tar.gz rpm -Uvh openssh-9.1p1-1.tl2.x86_64.rpm op…

第十四届蓝桥杯 子串简写 | 树状数组解法

Problem: 第十四届蓝桥杯 子串简写 程序猿圈子里正在流行一种很新的简写方法&#xff1a; 对于一个字符串&#xff0c;只保留首尾字符&#xff0c;将首尾字符之间的所有字符用这部分的长度代替。 例如 internationalization 简写成 i18n&#xff0c;Kubernetes 简写成 K8s&am…

npx\pnpm 镜像过期解决方法

. // 1. 清空缓存 npm cache clean --force // 2. 关闭SSL验证 npm config set strict-ssl false // 3. 安装 到这里就可以正常使用npm命令安装需要的工具了。如( npm install -g cnpm )