MyBatis 之缓存机制核心解析

目录

[1. 缓存](#1. 缓存)

[2. 一级缓存](#2. 一级缓存)

[2.1. 清空一级缓存](#2.1. 清空一级缓存)

[3. 二级缓存](#3. 二级缓存)

[4. 总结](#4. 总结)


前言

大家好,我是艺杯羹(๑•̀ㅂ•́)و✧

本文来讲解MyBatis中的缓存,旨在帮助读者更好的理解和掌握(๑•̀ㅂ•́)و✧

个人主页:艺杯羹

系列专栏:MyBatis

1. 缓存

缓存是内存当中一块存储数据的区域 ,目的是提高查询效率

MyBatis会将查询结果存储在缓存当中,当下次执行相同的SQL时不访问数据库,而是直接从缓存中获取结果,从而减少服务器的压力

  • 什么是缓存?

    存在于内存中的一块数据

  • 缓存有什么作用?

    减少程序和数据库的交互,提高查询效率降低服务器 和数据库的压力

  • 什么样的数据使用缓存?

    经常查询但不常改变的,改变后对结果影响不大的数据

  • MyBatis 缓存分为哪几类?

    一级缓存和二级缓存

  • 如何判断两次 Sql 是相同的?

    1. 查询的 Sql 语句相同
    2. 传递的参数值相同
    3. 对结果集的要求相同
    4. 预编译的模板 Id 相同

2. 一级缓存

MyBatis一级缓存也叫本地缓存

SqlSession对象中包含一个Executor对象 ,Executor对象中包含一个PerpetualCache对象,在该对象存放一级缓存数据

MyBatis的一级缓存是默认开启的,不需要任何的配置

测试一级缓存

java 复制代码
@Test
public void testCache1() throws IOException {
  InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  SqlSessionFactory factory = builder.build(is);
  SqlSession session = factory.openSession();


  // 使用同一个SqlSession查询
  UserMapper mapper1 = session.getMapper(UserMapper.class);
  UserMapper mapper2 = session.getMapper(UserMapper.class);


  User user1 = mapper1.findById(1);
  System.out.println(user1.hashCode());
  System.out.println("-------------------------------------------");
  User user2 = mapper2.findById(1);
  System.out.println(user2.hashCode());
}


@Test
public void testCache2() throws IOException {
  InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  SqlSessionFactory factory = builder.build(is);
  SqlSession session1 = factory.openSession();
  SqlSession session2 = factory.openSession();


  // 使用不同的SqlSession查询
  UserMapper mapper1 = session1.getMapper(UserMapper.class);
  UserMapper mapper2 = session2.getMapper(UserMapper.class);


  User user1 = mapper1.findById(1);
  System.out.println(user1.hashCode());
  System.out.println("-------------------------------------------");
  User user2 = mapper2.findById(1);
	// 看是否是一个对象
  System.out.println(user2.hashCode());
}

2.1. 清空一级缓存

进行以下操作可以清空MyBatis一级缓存

  1. SqlSession调用close(): 操作后SqlSession对象不可用,该对象的缓存数据也不可用
  2. SqlSession调用clearCache() / commit(): 操作会清空一级缓存数据
  3. SqlSession调用增删改方法: 操作会清空一级缓存数据,因为增删改后数据库发生改变,缓存数据将不准确

代码示范

java 复制代码
@Test
public void testCache3() throws IOException {
  InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  SqlSessionFactory factory = builder.build(is);
  SqlSession session = factory.openSession();


  UserMapper mapper1 = session.getMapper(UserMapper.class);
  UserMapper mapper2 = session.getMapper(UserMapper.class);


  User user1 = mapper1.findById(1);
  System.out.println(user1.hashCode());
  //     session.close();
  //     session.clearCache();
  //     session.commit();
  mapper1.delete(2);
  System.out.println("-------------------------------------------");
  User user2 = mapper2.findById(1);
  System.out.println(user2.hashCode());
}

3. 二级缓存

MyBatis二级缓存也叫全局缓存。数据存放在SqlSessionFactory中,只要是同一个工厂对象创建的SqlSession,在进行查询时都能共享数据。一般在项目中只有一个SqlSessionFactory对象,所以二级缓存的数据是全项目共享的

MyBatis一级缓存存放的是对象,二级缓存存放的是对象的数据

所以要求二级缓存存放的POJO必须是可序列化的,也就是要实现Serializable接口

MyBatis二级缓存默认不开启,手动开启后数据先存放在一级缓存中,只有一级缓存数据清空后,数据才会存到二级缓存中

注:SqlSession调用 clearCache() 无法将数据存到二级缓存中(直接清空一级缓存的当前数据)

开启二级缓存

  1. POJO类实现Serializable接口
java 复制代码
public class User implements Serializable {
  private int id;
  private String username;
  private String sex;
  private String address;
}
  1. 在MyBatis配置文件添加如下设置:
XML 复制代码
<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>

由于cacheEnabled默认值是true,所以该设置可以省略

  1. 在映射文件(UserMapper.xml)添加<cache />​标签,该映射文件下的所有方法都支持二级缓存如果查询到的集合中对象过多,二级缓存只能缓存1024个对象引用。可以通过<cache />​标签的size属性修改该数量
    <cache size="2048"/>

  2. 测试二级缓存

java 复制代码
@Test
public void testCache4() throws IOException {
  InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
  SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
  SqlSessionFactory factory = builder.build(is);
  SqlSession session1 = factory.openSession();
  SqlSession session2 = factory.openSession();


  UserMapper mapper1 = session1.getMapper(UserMapper.class);
  UserMapper mapper2 = session2.getMapper(UserMapper.class);


  User user1 = mapper1.findById(1);
  System.out.println(user1);
  System.out.println(user1.hashCode());
  // 让一级缓存失效
  session1.commit();
  System.out.println("-------------------------------------------");


  User user2 = mapper2.findById(1);
  System.out.println(user2);
  System.out.println(user2.hashCode());
}

4. 总结

对比项 一级缓存(本地缓存) 二级缓存(全局缓存)
存储位置 SqlSession 的 Executor 中的 PerpetualCache SqlSessionFactory
开启方式 默认开启,无需配置 默认不开启,需手动配置
共享范围 仅同一 SqlSession 内共享 同一 SqlSessionFactory 创建的 SqlSession 共享
存储内容 完整对象 对象数据(需 POJO 实现 Serializable 接口)
生效关键条件 同一 SqlSession 执行相同 SQL 一级缓存清空后,同一 SqlSessionFactory 下执行相同 SQL
核心清空场景 SqlSession 调用 close ()/clearCache ()/commit ()、执行增删改操作 对应增删改操作、配置失效等

到此,缓存就讲解完了,希望对大家有所帮助(๑•̀ㅂ•́)و✧

相关推荐
天天进步20152 分钟前
设计模式在Java中的实际应用:单例、工厂与观察者模式详解
java·观察者模式·设计模式
thginWalker7 分钟前
Java JVM
java·jvm
是Yu欸12 分钟前
【浏览器插件冲突】Edge浏览器加载不出来CSDN创作者中心
java·数据库·edge
中东大鹅24 分钟前
SpringBoot配置文件
java·spring boot·spring
鼠鼠我捏,要死了捏40 分钟前
深入解析JVM垃圾回收调优:性能优化实践指南
java·jvm·gc
笑衬人心。1 小时前
后端项目中大量 SQL 执行的性能优化
sql·spring·性能优化
都叫我大帅哥1 小时前
TOGAF数据架构阶段完全指南:从理论到Java实战
java
Micro麦可乐1 小时前
前端与 Spring Boot 后端无感 Token 刷新 - 从原理到全栈实践
前端·spring boot·后端·jwt·refresh token·无感token刷新
方块海绵1 小时前
浅析 MongoDB
后端
中东大鹅2 小时前
SpringBoot配置外部Servlet
spring boot·后端·servlet