MyBatis学习 | 缓存机制

news2025/1/18 18:56:32

文章目录

  • 一、一级缓存
    • 1.1 简介
    • 1.2 一级缓存的失效情况
  • 二、二级缓存
    • 2.1 简介
    • 2.2 二级缓存的使用


学习地址🔗

  • https://www.bilibili.com/video/BV1mW411M737
  • https://www.bilibili.com/video/BV1NE411Q7Nx
  • 官网文档

一、一级缓存

1.1 简介

💬概述:一级缓存也称为本地缓存、SqlSession级别的缓存

🔑特点

  • 一级缓存是一直开启的,不能手动关闭
  • 一级缓存的作用域是MyBatis与数据库之间的一次会话,在本次会话间第一次查询出来的数据都会放到一级缓存中(本地缓存)
  • 一个SqlSession会话对象对应一个一级缓存,因为SqlSession对象就代表MyBatis与数据库的一次会话
  • 一级缓存相当于SqlSession级别的一个Map集合,在本次会话中查询相同数据时,就不会再访问数据库,而是直接从该Map集合(一级缓存)中获取,可以大大加快访问速度

🔑测试:在与数据库的一次会话间查询两次相同的对象数据,然后比较两个对象是否是同一个对象

  • 测试方法

    @Test
    public void testFirstLevelCache() {
        // 获取SqlSession对象(代表一次会话)
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
    
        // 获取mapper对象
        UserDao mapper = sqlSession.getMapper(UserDao.class);
    
        // 第一次查询员工user1
        User user1 = mapper.getUserById(2);
        System.out.println(user1);
    
        // 再次查询员工user2
        User user2 = mapper.getUserById(2);
        System.out.println(user2);
    
        // 比较两个对象是否相同
        System.out.println("查询的两个对象是否相同 --> " + (user1 == user2));
    
        // 关闭sqlSession
        sqlSession.close();
    }
    
  • 打印结果test-first-level-cache

  • 结果分析

    1. 控制台的打印结果中只有一条SQL语句,说明MyBatis只发送了一条SQL语句给数据库,也就是说MyBatis与数据库只进行了一次交互
    2. 打印结果中可以看到两个对象的比较结果是true,说明两次查询出的对象是相同的
    3. 第一次查询对象user1时,此时本地缓存(一级缓存)中还没有对应的对象,因此MyBatis就会访问数据库获取对应数据,然后再把获取到的对象数据存储到本地缓存中;当第二次再查询相同id的对象user2时,MyBatis就会直接到缓存中查找对应数据,而不会再去访问数据库,因此也只会发送一次SQL语句

1.2 一级缓存的失效情况

💬概述:是一级缓存是SqlSession级别的缓存,只在一次会话间生效,SqlSession对象发生改变(当前会话不一定结束)时一级缓存就有可能会失效

🔑四种失效情况

  • 两次查询一样的数据,但使用的SqlSession对象不同

    • 测试方法

      @Test
      public void testFirstLevelCacheLose() {
          // 获取SqlSession01
          SqlSession sqlSession01 = MyBatisUtil.getSqlSession();
      
          // 直接查询对象user01
          User user01 = sqlSession01.getMapper(UserDao.class).getUserById(1);
          System.out.println(user01);
      
          // 获取SqlSession02
          SqlSession sqlSession02 = MyBatisUtil.getSqlSession();
      
          // 直接查询对象user02
          User user02 = sqlSession02.getMapper(UserDao.class).getUserById(1);
          System.out.println(user02);
      
          // 比较两个对象是否相同
          System.out.println("查询的两个对象是否相同 --> " + (user01 == user02));
      
          // 关闭两个sqlSession
          sqlSession01.close();
          sqlSession02.close();
      }
      
    • 打印结果test-first-level-cache-lose01

  • 同一个SqlSession对象下,两次查询不一样的数据

    • 测试方法

      @Test
      public void testFirstLevelCacheLose() {
          // 获取SqlSession01
          SqlSession sqlSession01 = MyBatisUtil.getSqlSession();
      
          UserDao mapper = sqlSession01.getMapper(UserDao.class);
      
          // 直接查询对象user01
          User user01 = mapper.getUserById(1);
          System.out.println(user01);
      
          // 直接查询对象user02
          User user02 = mapper.getUserById(2);
          System.out.println(user02);
      
          // 比较两个对象是否相同
          System.out.println("查询的两个对象是否相同 --> " + (user01 == user02));
      
          // 关闭sqlSession
          sqlSession01.close();
      }
      
    • 打印结果test-first-level-cache-lose02

  • 同一个SqlSession对象下,两次查询一样的数据,但在第二次查询前执行一次增删改操作

    • 测试方法

      @Test
      public void testFirstLevelCacheLose() {
          // 获取SqlSession01
          SqlSession sqlSession01 = MyBatisUtil.getSqlSession();
      
          UserDao mapper = sqlSession01.getMapper(UserDao.class);
      
          // 直接查询对象user01
          User user01 = mapper.getUserById(1);
          System.out.println(user01);
      
          // 添加一条数据
          int result = mapper.insertUserBySqlAndInclude(new User(null, "刘唐", "liu123"));
          if (result != 0) {
          	System.out.println("插入成功!");
          }
      
          // 直接查询对象user02
          User user02 = mapper.getUserById(1);
          System.out.println(user02);
      
          // 比较两个对象是否相同
          System.out.println("查询的两个对象是否相同 --> " + (user01 == user02));
      
          // 关闭sqlSession
          sqlSession01.close();
      }
      
    • 打印结果test-first-level-cache-lose03

  • 同一个SqlSession对象下,两次查询一样的数据,但在第二次查询前将缓存清空(调用SqlSession对象的clearCache()方法)

    • 测试方法

      @Test
      public void testFirstLevelCacheLose() {
          // 获取SqlSession01
          SqlSession sqlSession01 = MyBatisUtil.getSqlSession();
      
          UserDao mapper = sqlSession01.getMapper(UserDao.class);
      
          // 直接查询对象user01
          User user01 = mapper.getUserById(1);
          System.out.println(user01);
      
          // 清空本地缓存
          sqlSession01.clearCache();
          System.out.println("本地缓存已清空...");
      
          // 直接查询对象user02
          User user02 = mapper.getUserById(1);
          System.out.println(user02);
      
          // 比较两个对象是否相同
          System.out.println("查询的两个对象是否相同 --> " + (user01 == user02));
      
          // 关闭sqlSession
          sqlSession01.close();
      }
      
    • 打印结果test-first-level-cache-lose04


二、二级缓存

2.1 简介

💬概述:MyBatis还提供了二级缓存机制,二级缓存也称为全局缓存,范围比一级缓存更大

🔑特点

  • 二级缓存是基于namespace级别的缓存,一个namespace对应一个二级缓存,即一个SQL映射文件对应一个二级缓存,也相当于一个dao接口对应一个二级缓存
  • 二级缓存在MyBatis底层也是一个Map集合,作用域是整个mapper,是namespace级别的Map集合

🔑工作机制

  • 在一次会话中,即一个SqlSession对象中查询的数据会先放入当前会话对应的本地缓存(一级缓存)中

  • 当前会话关闭后,MyBatis不会将会话对应的一级缓存中数据清空,而是会将数据转移到对应mapper的二级缓存

    ❓ 关于缓存数据的转移

    • 一定是会话关闭后,即执行sqlSession.close()后,一级缓存中的数据才会被转移到二级缓存,如果当前会话还没有关闭,数据还是只在一级缓存中
    • MyBatis是通过序列化和反序列的方式将数据从一级缓存克隆到二级缓存中,因此二级缓存和一级缓存中的数据内容虽然是一样的,但却不是同一份数据
  • 当新的会话创建时,即创建新的SqlSession对象查询数据时,如果开启了全局二级缓存,则MyBatis会先从二级缓存中查询对应数据,如果二级缓存中查询不到,才会到一级缓存中查询,如果一级缓存中也没有,最后才访问数据库查找

2.2 二级缓存的使用

  • 开启全局二级缓存配置:在全局配置文件的<setting>标签中设置cacheEnabled参数,并设置为true

    <!-- 设置MyBatis运行时的参数 -->
    <settings>
        <!-- 开启全局二级缓存配置 -->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  • 在映射文件中添加<cache>标签:直接在对应的映射文件中添加<cache>标签(与其他SQL语句标签同级),<cache>里面的属性可以不设置,MyBatis已经设置好了默认值

    <mapper namespace="com.key.mybatis.dao.UserDao">
    	<!-- 在当前映射文件中开启二级缓存 -->
        <cache/>
    </mapper>
    
  • 在映射文件对应的JavaBean中实现序列化接口:在对应的JavaBean类中实现序列化接口——Serializable

    public class User implements Serializable {
    
        /**
         * 序列化id
         */
        private static final long serialVersionUID = -6976094896694250242L;
    
        private Integer userid;
        private String username;
        private String password;
    
        public User() {
        }
        
        // code...
    }
    
  • 测试方法

    @Test
    public void testSecondLevelCache() {
        // 获取两个sqlSession
        SqlSession sqlSession01 = MyBatisUtil.getSqlSession();
        SqlSession sqlSession02 = MyBatisUtil.getSqlSession();
    
        // 使用sqlSession01查询数据
        User user01 = sqlSession01.getMapper(UserDao.class).getUserById(4);
        System.out.println(user01);
    
        // 关闭sqlSession01
        sqlSession01.close();
    
        // 使用sqlSession02查询相同的数据
        User user02 = sqlSession02.getMapper(UserDao.class).getUserById(4);
        System.out.println(user02);
    
        // 再关闭sqlSession02
        sqlSession02.close();
    
        // 比较获取的两个对象是否是同一个
        System.out.println("两个数据是否相同 --> " + (user01 = user02));
    }
    
  • 打印结果test-second-level-cache-result

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

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

相关文章

Spring与SpringBoot

目录 前言 1、Spring能做什么 1.1、Spring的能力 1.2、Spring的生态 1.3、Spring5重大升级 1.3.1、响应式编程 1.3.2、内部源码设计 2、为什么用SpringBoot 2.1、SpringBoot优点 2.2、SpringBoot缺点 3、时代背景 3.1、微服务 3.2、分布式 分布式的困难 分布式的…

迪文DGUS智能屏如何轻松实现3D动画

三维立体的视觉效果已经被广泛应用于人机交互中&#xff0c;三维图形逼真的显示效果往往可以更加直接的传递出视觉信息&#xff0c;减少用户的信息解读门槛。 传统的三维立体静态、动态画面的显示往往对于 GPU 的图像处理性能、显示带宽有较高要求&#xff0c;GPU 需要完成图形…

使用gs_probackup进行数据库物理备份与恢复

概述 物理备份与恢复适用于数据量大的场景&#xff0c;主要用于全量数据备份恢复&#xff0c;也可对整个数据库中的WAL归档日志和运行日志进行备份。openGauss提供了三种物理备份与恢复相关的工具&#xff1a;gs_backup、gs_basebackup和gs_probackup。三个工具的对比见下图。…

基于FPGA的时间数字转换(TDC)设计(二)

1、多相位TDC计时FPGA代码设计 接上期的讲解,本期主要讲多相位TDC计时的FPGA代码实现。图1为TDC测量实现系统图。时间信号经过探测器后,转换为电信号,一般探测器出来的信号幅度和脉宽都比较小,需要时间鉴别器进行比较和整形,以便于FPGA能够识别。经过FPGA TDC计时模块后,…

RabbitMQ:订阅模型-消息订阅模式

订阅模型-消息订阅模式&#xff0c;也可以称为广播模式&#xff0c;生产者将消息发送到 Exchange&#xff0c;Exchange 再转发到与之绑定的 Queue中&#xff0c;每个消费者再到自己的 Queue 中取消息。 RabbitMQ 单生产单消费模型主要有以下五个角色构成&#xff1a; 生产者&am…

机器学习10大经典算法详解

“数据算法模型”。 面对具体的问题&#xff0c;选择切合问题的模型进行求解十分重要。有经验的数据科学家根据日常算法的积累&#xff0c;往往能在最短时间内选择更适合该问题的算法&#xff0c;因此构建的模型往往更准确高效。本文归纳了机器学习的10大算法&#xff0c;并分别…

Python基础语法(一)

Python基础语法 文章目录Python基础语法基础语法变量的语法(1) 定义变量(2) 使用变量变量的类型(1) 整数(2) 浮点数(小数)(3) 字符串(4) 布尔(5) 其他动态类型特性输入输出注释通过控制台输出通过控制台输入运算符算术运算符关于除法// 取整除法关系运算符逻辑运算符关于短路求…

美格智能Cat.1无线POS终端解决方案,引领消费支付新场景

近年来&#xff0c;随着我国移动互联网的蓬勃发展和智能手机的快速渗透&#xff0c;移动支付在我国全面普及。尤其是后疫情时代下&#xff0c;无接触观念的普及&#xff0c;使我国消费市场形成了以移动支付为主的消费习惯&#xff0c;并催生了万千移动支付场景终端的数字化、智…

磁盘被写保护怎么办?5个方案解除它

硬盘、移动硬盘、U盘、SD卡和TF卡&#xff08;也称为手机存储卡&#xff09;具有写保护功能。当它们出现写保护的状态&#xff0c;我们就没有办法在里面写入数据。具体而言&#xff0c;就是无法保存和删除文件。磁盘被写保护怎么办&#xff1f;你需要下面5个方案帮助你&#xf…

20221227英语学习

今日短文 How to Become an Expert 想成为行业的专家&#xff1f;不是只花时间就够了 The drive to become expert – to become as good as we can be, at whatever we’ve chosen to do – is something we all share.It is not about external markers of success.It’s a…

01【WEB开发、Servlet】

文章目录01【WEB开发、Servlet】一、WEB开发简介1.1 什么是WEB开发1.2 软件的架构1.2.1 BS和CS概述1.2.2 WEB资源的类别1&#xff09;静态网站的特点&#xff1a;2&#xff09;动态网站的特点&#xff1a;1.3 Web服务器1.3.1 什么是服务器&#xff08;硬件&#xff09;1.3.2 什…

再也不愁渲染素材了?AI 生成3D纹理 #Polycam3D 推出新功能

最近有不少群友运用 AIGC 工具来提升工作效率&#xff0c;我听说连 3D 数字资产的渲染贴图素材都能生成了。Mixlab小杜3D 内容制作工具也是我非常感兴趣的领域&#xff0c;Polycam3D 本是一款扫描建模工具&#xff0c;近期也推出了AI生成3D纹理的功能&#xff0c;推荐大家去尝试…

启封化工行业ERP方案 ---危险化学品的备案管理

目录 危险化学品的备案管理制度 易制毒制爆危险化学品采购流程 Sage X3 ERP 危化品备案管理方案 危险化学品的备案管理制度 不少化工企业在日常的生产经营过程中&#xff0c;都有可能会涉及到易制毒、易制爆相关的危险化学品的购买和使用&#xff0c;由于易制爆、易制毒危险…

Vue组件、组件通信、路由、axios、$event、$refs、跨域代理、element-ui

文章目录{ { } }插值表达式$eventv-for删除、新增axios方法优化启动 Vue项目Vue项目的运行流程组件的三个结构组件的使用组件之间的通信父子 组件通信兄弟组件通信操作DOM插槽 slot移除node_modules路由安装、入门嵌套路由获取路由参数跨域代理element-ui表单验证Message 消息提…

基于Java+SQL Server开发(PC)学生管理系统【100010054】

题目学生管理系统 一、摘要 在当今互联网行业&#xff0c;Java 的使用及热度在各大排行榜中始终位于前列&#xff0c;通过本次课程设计&#xff0c;巩固所学 Java 知识&#xff0c;了解 Java 项目的开发流程。本程序是使用 Java 开发的一款学生管理系统&#xff0c;设计中使用…

微信开放小程序SDK,几款SDK产品对比分析

前言 这几天看到微信团队推出了一个名为 Donut 的小程序原生语法开发移动应用框架&#xff0c;通俗的讲就是将微信小程序的能力开放给其他的企业&#xff0c;第三方的 App 也能像微信一样运行小程序了。 其实不止微信&#xff0c;面对广阔的B端市场&#xff0c;阿里也早已开放…

kafka学习笔记

1. 官网 ​​​​​​​​​​​​​​​​​​​​​​​​​Apache Kafka 2. akf X轴拆分: 水平复制&#xff0c;就是讲单体系统多运行几个实例&#xff0c;做集群加负载均衡的模式,主主、主备、主从。解决单点&#xff0c;高可用问题 Y轴拆分: 基于不同的业务拆分 Z轴拆…

年底了,千万不要跳槽。

最近不少人在私信问我&#xff1a;做了几年 Java 工程师&#xff0c;现在很迷茫&#xff0c;想跳槽但是感觉底气不足&#xff0c;不知道如何是好。 作为一个资历不浅的 Java 开发&#xff0c;这几年我面试过不少人。发现大多数面试者&#xff0c;虽然看起来工作努力&#xff0…

FPGA 点亮LED灯

设计流程 首先对项目要有一个全局的考虑&#xff0c;分析项目需要几个模块构成&#xff0c;确定各个子模块的关系和信号之间 的相互关系&#xff0c;然后确定模块的端口信号有哪些&#xff1b;根据每个模块的功能并结合芯片、接口的时序手册画 出该模块能正常工作的时序波形图…

CSS3【垂直对齐方式、光标类型、 边框圆角 、overflow溢出部分显示效果 、元素本身隐藏】

文章目录二、装饰2.1 认识基线&#xff08;了解&#xff09;2.2 文字对齐问题2.3 垂直对齐方式2.4 小结2.5&#xff08;拓展&#xff09;项目中 vertical-align 可以解决的问题2.6 光标类型2.7 边框圆角2.8 边框圆角的常见应用2.9 小结2.10 溢出部分显示效果2.11 小结2.12 元素…