当前位置: 首页 > news >正文

MyBatis系统学习篇 - MyBatis的缓存

MyBatis的缓存实现原理主要基于三级缓存机制,包括一级缓存(本地缓存)、二级缓存(全局缓存)和三级缓存(跨会话缓存)。这个缓存在我们实际开发中可以避免我们查询重复的数据,在一定程度上可以帮助我们减少对数据库同一数据的重复查询,也可以在一定程度上使用MyBatis缓存可以帮助我们更好的查询数据和进行数据交互,减少对数据库的数据查询次数吧。

一级缓存

MyBatis一级缓存也可以称作本地缓存,他是SqlSession级别的缓存,默认开启,可以减少我们对数据库的重复查询,当执行查询的时候,查询结果会被存储在SqlSession中的本地存储中,在同一个Session中,如果执行相同的查询,MyBatis会从本地缓存中查找结果,如果找到则直接返回,否则再去数据库中查询并存储到本地缓存中。

一级缓存的实现

// 在MyBatis配置文件中开启一级缓存
<configuration><settings><setting name="localCacheScope" value="SESSION"/></settings>
</configuration>
public static void main(String[] args) {try (SqlSession sqlSession = sqlSessionFactory.openSession()) {EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);// 测试一级缓存Emp emp1 = empMapper.getEmpById(1); // 第一次查询,会从数据库中获取数据Emp emp2 = empMapper.getEmpById(1); // 第二次查询,会从一级缓存中获取数据System.out.println(emp1 == emp2); // 输出:true,说明从一级缓存中获取到了同一个对象}}

一级缓存失效的几种情况:

  • 不同的SqlSession:一级缓存是基于SqlSession的,当使用不同的SqlSession对象执行相同的查询时,一级缓存会失效。因为每个SqlSession都有自己的本地缓存,无法共享缓存数据。

  • 手动清空缓存:通过调用SqlSessionclearCache()方法可以手动清空一级缓存。这样会导致之前缓存的数据被清除,下一次查询会重新从数据库中获取数据。

  • 更新操作:当执行了插入、更新或删除操作时,可能会影响到缓存中的数据。MyBatis会自动将更新操作同步到缓存中,但是会清空相关的缓存数据,以保证缓存的数据与数据库的数据一致。

  • 缓存大小限制:一级缓存的大小是有限的,默认情况下,一级缓存的大小为1024个对象。当缓存中的对象数量达到上限时,新的查询结果会导致最早的查询结果被淘汰出缓存,从而失效。

  • 手动提交事务:如果在执行查询之前手动提交了事务(调用了commit()方法),则会导致一级缓存失效。因为事务提交后,会关闭当前的SqlSession,同时清空一级缓存。

二级缓存

MyBatis二级缓存也可以被称作全局缓存,一般上是默认关闭的,并且配置方式也与一级缓存有区别,需要我们在具体的mapper映射文件中手动配置开启。

二级缓存开启的条件:
因为二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果被缓存,伺候再次执行相同的查询语句就可以直接从缓存中获取。

  • 在核心配置文件中,设置全局配置属性cacheEnable="true",默认true,一般不需要设置
  • 在映射文件中配置<cache />
  • 二级缓存必须在SqlSession关闭或者提交后有效
  • 查询的数据所转换的实体类类型必须实现序列化的接口。

当我们开启二级缓存的时候,查询的结果会被存储在Mapper的全局缓存中,多个SqlSession可以共享同一个Mapper的二级缓存,在执行查询的时候,MyBatis会从我们的二级缓存中查询结果,如果找到则直接返回,如果没有找到,那么就会去数据库中查询,并存储到二级缓存中。

// 在Mapper接口对应的映射文件中开启二级缓存
<cache/>
  public static void main(String[] args) {try (SqlSession sqlSession = sqlSessionFactory.openSession()) {EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);// 测试二级缓存SqlSession sqlSession2 = sqlSessionFactory.openSession();EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);Emp emp3 = empMapper2.getEmpById(1); // 第一次查询,会从数据库中获取数据sqlSession2.close(); // 关闭SqlSessionSqlSession sqlSession3 = sqlSessionFactory.openSession();EmpMapper empMapper3 = sqlSession3.getMapper(EmpMapper.class);Emp emp4 = empMapper3.getEmpById(1); // 第二次查询,会从二级缓存中获取数据sqlSession3.close();System.out.println(emp3 == emp4); // 输出:true,说明从二级缓存中获取到了同一个对象}}

cache标签的配置属性值

  • eviction:指定缓存的回收策略,用于决定在缓存达到上限时如何清理缓存。常用的回收策略包括:

    • LRU(Least Recently Used):最近最少使用,根据最近的访问时间来淘汰数据。
    • FIFO(First In, First Out):先进先出,根据数据最早进入缓存的时间来淘汰数据。
    • SOFT:软引用,根据JVM的垃圾回收机制来决定是否清理缓存数据。
    • WEAK:弱引用,类似于软引用,但更容易被垃圾回收器回收。
  • flushInterval:指定缓存刷新间隔,表示缓存刷新的时间间隔,单位为毫秒。设置了该属性后,缓存会定期刷新,以保证缓存数据的有效性。

  • readOnly:指定缓存是否为只读,如果设置为true,表示缓存数据不会被修改,可以提高缓存的性能。

  • size:指定缓存的大小限制,表示缓存中可以存储的对象数量上限。当缓存中的对象数量达到该上限时,会根据回收策略进行数据清理。

  • type:指定缓存的实现类型,可以是MyBatis提供的内置缓存实现,也可以是自定义的缓存实现。常用的内置缓存实现包括:

    • PERPETUAL:永久缓存,数据永久保存在缓存中。
    • FIFO:先进先出缓存。
    • LRU:最近最少使用缓存。
    • SOFT:软引用缓存。
    • WEAK:弱引用缓存。

示例配置:

<cacheeviction="LRU"flushInterval="60000"readOnly="false"size="1024"type="PERPETUAL"/>

MyBatis缓存查询顺序:

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿出来使用,如果二级缓存没有命中,那就在查一级缓存,如果一级缓存也没有命中,那就查询数据库。SqlSession关闭后,以及缓存中的数据会写入到二级缓存中。

二级缓存失效的几种原因:

数据更新:当执行了插入、更新或删除操作时,会导致与这些操作相关的缓存数据失效。MyBatis会自动将更新操作同步到缓存中,但也会清空相关的缓存数据,以保证缓存中的数据与数据库的数据一致。

并发操作:在并发环境下,如果多个线程同时对同一条数据进行更新操作,可能会导致缓存中的数据与数据库中的数据不一致。这时需要考虑缓存的并发控制策略,以避免脏数据的产生。

查询结果不满足缓存条件:MyBatis的二级缓存对查询结果有一定的条件限制,例如查询结果的类型必须是可序列化的、不能包含动态SQL等。如果查询结果不满足这些条件,可能会导致缓存失效。

缓存大小限制:二级缓存的大小是有限的,当缓存中的对象数量达到上限时,新的查询结果会导致最早的查询结果被淘汰出缓存,从而失效。

手动清空缓存:通过调用SqlSession的clearCache()方法可以手动清空二级缓存。这样会导致之前缓存的数据被清除,下一次查询会重新从数据库中获取数据。

事务提交:如果在执行查询之前手动提交了事务(调用了commit()方法),则会导致二级缓存失效。因为事务提交后,会关闭当前的SqlSession,同时清空二级缓存。

三级缓存

三级缓存是一种跨会话级别的缓存,他通过与外部缓存系统,例如Redis,Memcached等进行实现。通过外部缓存系统的集成,进而实现多个应用实例之间的缓存共享,从而提高缓存的利用率和拓展性。

关于三级缓存,无法依靠MyBatis单独实现,因为他本事不提供直接对外缓存系统的集成,故而无法实现一个完整的三级缓存示例,然而,可以通过MyBatis的扩展插件或者自定义实现来集成外部缓存系统,例如:Redis,Memcached等。
我们采用Redis自定义实现Mybatis的三级缓存。
首先,需要引入MyBatis的扩展插件,例如MyBatis Redis Cache,它是一个MyBatis的缓存插件,可以将缓存数据存储到Redis中。

然后,需要在MyBatis的配置文件中配置该插件,指定Redis作为缓存的实现:

<configuration><settings><setting name="cacheEnabled" value="true"/></settings><typeAliases><!-- 定义需要缓存的实体类别名 --></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!-- 配置数据源信息 --></dataSource></environment></environments><mappers><!-- 配置Mapper接口 --></mappers><plugins><plugin interceptor="org.mybatis.caches.redis.RedisCache"/></plugins>
</configuration>

<plugin>标签配置了MyBatis Redis Cache插件,将Redis作为缓存的实现。

接下来,可以在Java代码中进行测试,通过调用Mapper接口的方法来触发缓存的使用:

public class MyBatisCacheTest {public static void main(String[] args) {try (SqlSession sqlSession = sqlSessionFactory.openSession()) {EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);// 调用Mapper接口的方法进行查询Emp emp1 = empMapper.getEmpById(1); // 第一次查询,会从数据库中获取数据Emp emp2 = empMapper.getEmpById(1); // 第二次查询,会从Redis缓存中获取数据System.out.println(emp1 == emp2); // 输出:true,说明从Redis缓存中获取到了同一个对象}}
}

实际的三级缓存实现可能会更加复杂,涉及到缓存的清理、失效策略、缓存击穿和雪崩等问题,需要根据实际情况进行更加细致的配置和测试。

http://www.lryc.cn/news/351335.html

相关文章:

  • K-means聚类模型
  • 免费分享一套微信小程序旅游推荐(智慧旅游)系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】,帅呆了~~
  • Matlab 2023b学习笔记1——界面认识
  • C++ sort排序的总和应用题
  • [力扣]——231.2的幂
  • 【css】引入背景图时候,路径写入@会报错
  • 【有手就行】使用你自己的声音做语音合成,CPU都能跑,亲测有效
  • 《ESP8266通信指南》番外-(附完整代码)ESP8266获取DHT11接入(基于Lua)
  • [IMX6ULL驱动开发]-Linux对中断的处理(一)
  • PHP基础学习笔记(面向对象OOP)
  • Mysql超详细安装配置教程(保姆级图文)
  • HR招聘测评,如何判断候选人的团队协作能力?
  • [STM32-HAL库]Flash库-HAL库-复杂数据读写-STM32CUBEMX开发-HAL库开发系列-主控STM32F103C6T6
  • windows 下访问 csdn 异常问题
  • vue3结合element-plus之如何优雅的使用表格
  • 网络协议——Modbus-RTU
  • 【Qt】如何优雅的进行界面布局
  • 【八股系列】分别说一下nodeJS和浏览器的事件循环机制?
  • 关于基础的流量分析(1)
  • 数据结构---树,二叉树的简单概念介绍、堆和堆排序
  • MySQL聚合函数(多行函数)
  • 智慧教室课堂-专注度及考试作弊系统、课堂动态点名,情绪识别、表情识别和人脸识别结合
  • 单例模式简要介绍
  • 深度学习面试问题总结(21)| 模型优化
  • 4月手机行业线上市场销售数据分析
  • 首都师范大学聘请旅美经济学家向凌云为客座教授
  • 多电脑共享鼠标键盘
  • 展厅设计对企业有哪些作用
  • LeetCode-102. 二叉树的层序遍历【树 广度优先搜索 二叉树】
  • 基于时频模糊算子的数据增强方法