MyBatis 之缓存机制核心解析

目录

1. 缓存

2. 一级缓存

2.1. 清空一级缓存

 3. 二级缓存

 4. 总结


前言

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

个人主页:艺杯羹

系列专栏:MyBatis

1. 缓存

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

  • 什么是缓存?
    存在于内存中的一块数据

  • 缓存有什么作用?
    减少程序和数据库的交互,提高查询效率降低服务器和数据库的压力

  • 什么样的数据使用缓存?
    经常查询但不常改变的,改变后对结果影响不大的数据

  • MyBatis 缓存分为哪几类?
    一级缓存和二级缓存

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

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

2.  一级缓存

MyBatis一级缓存也叫本地缓存
SqlSession对象中包含一个Executor对象,Executor对象中包含一个PerpetualCache对象,在该对象存放一级缓存数据
MyBatis的一级缓存是默认开启的,不需要任何的配置

测试一级缓存

@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​调用增删改方法: 操作会清空一级缓存数据,因为增删改后数据库发生改变,缓存数据将不准确

代码示范

@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接口

public class User implements Serializable {
  private int id;
  private String username;
  private String sex;
  private String address;
}

2.  在MyBatis配置文件添加如下设置:

<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>

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

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

4.  测试二级缓存

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

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

评论 21
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艺杯羹

你的鼓励是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值