MyBatis学习 | 缓存机制

24 篇文章 0 订阅


学习地址🔗

一、一级缓存

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis是一个开源的持久层框架,它可以帮助开发人员简化数据库操作。如果你想学习MyBatis,下面是一个学习路线的建议: 1. 数据库基础:在学习MyBatis之前,建议先掌握数据库的基本概念和SQL语言。了解关系型数据库的原理、表设计和常用的SQL语句会对学习MyBatis有很大帮助。 2. MyBatis入门:开始学习MyBatis之前,可以先了解一下MyBatis的基本概念和核心特性。阅读官方文档或者参考一些入门教程可以帮助你快速上手。 3. 配置文件:学习如何配置MyBatis的核心配置文件,包括数据源、映射文件、类型处理器等。了解不同配置项的作用和常用配置方式。 4. 映射文件:深入学习MyBatis的映射文件,了解如何使用SQL语句进行数据库操作,并学习动态SQL的使用技巧。掌握映射文件中各种标签的含义和用法。 5. 注解方式:学习使用注解方式来配置和使用MyBatis。了解常用的注解和使用方式,与映射文件相比,注解方式更加简洁和灵活。 6. 缓存机制:了解MyBatis缓存机制,包括一级缓存和二级缓存的原理和使用方式。了解如何配置和优化缓存,提高系统的性能。 7. 整合框架:学习如何将MyBatis与其他框架进行整合,如Spring和Spring Boot。掌握整合的配置方式和常见问题的解决方法。 8. 实践项目:通过实践项目来巩固所学的知识,可以自己动手搭建一个简单的Web应用或者实现一些常见的数据库操作。在实践中不断提升自己的技能。 以上是一个大致的学习路线,你可以根据自己的实际情况和学习进度进行调整。希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值