【Spring】Mybatis缓存+ehcache

文章目录

    • 基础缓存
    • 基于Spring的Mybatis缓存+ehcache
      • @Cacheable
      • @CachePut
      • @CacheEvict
      • @Caching

基础缓存

一级缓存

SqlSession 级别的缓存,它是默认开启的。每当执行一个查询操作时,MyBatis 会首先从一级缓存中查找结果,如果找到了相应的数据,则直接返回,不再执行查询 SQL。如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession 都会取出当前缓存的数据,而不会再次发送 SQL 到数据库。如果一级缓存中没有找到数据,才会发送 SQL 到数据库查询,并将查询结果存入一级缓存中。

一级缓存是线程不安全的,它仅适用于单个会话。

二级缓存

可以跨多个 SqlSession 共享。它是在命名空间级别的,也就是说,对于同一个 Mapper 接口(或 XML 映射文件),所有使用该 Mapper 的 SqlSession 可以共享一个二级缓存。二级缓存默认是关闭的,需要手动开启。

二级缓存的生命周期与应用程序的生命周期相同,或者至少与同一个 SQL 映射文件的使用周期相同。因此,二级缓存是线程安全的。

实现二级缓存的时候,MyBatis 要求返回的 POJO 必须是可序列化的。 也就是要求实现 Serializable 接口。

Mybatis 开启使用二级缓存

在 mybatis-config.xml 配置文件中开启二级缓存

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

在 mapper 映射文件中开启二级缓存

<!--回收策略为先进先出,每隔60秒刷新一次,最多缓存512个引用对象,只读-->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

eviction(收回策略)

  • LRU(最近最少使用的):移除最长时间不被使用的对象
  • FIFO(先进先出):按对象进入缓存的顺序来移除它们
  • SOFT(软引用):移除基于垃圾回收器状态和软引用规则的对象
  • WEAK(弱引用):更积极地移除基于垃圾收集器状态和弱引用规则的对象

flushInterval(刷新间隔):正整数,代表合理的毫秒形式的时间段。默认不设置,缓存仅仅调用语句时刷新

size(引用数目):正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值 1024

readOnly(只读):只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,默认 false

禁用缓存

useCache 默认值 true

<select id="findAllPets" resultMap="petsMap" useCache="false">select * from pets
</select>

刷新缓存

flushCache 查询语句中默认值 false,新增删除修改语句中默认值 true(清空缓存)

基于Spring的Mybatis缓存+ehcache

引入缓存的依赖包,在配置文件 pom.xml 中添加

<!--添加缓存-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId>
</dependency>

添加缓存的配置文件 ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"updateCheck="false"><!--指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下user.home :         用户主目录user.dir :          用户当前工作目录java.io.tmpdir :    默认临时文件路径--><diskStore path="java.io.tmpdir/Tmp_EhCache"/><!--name:                            缓存名称eternal:                         true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为falsetimeToIdleSeconds:               设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态timeToLiveSeconds:               设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义maxElementsInMemory:             内存中最大缓存对象数;maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行memoryStoreEvictionPolicy:       当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)maxElementsOnDisk:               硬盘中最大缓存对象数,若是0表示无穷大overflowToDisk:                  是否保存到磁盘,当系统宕机时diskPersistent:                  是否缓存虚拟机重启期数据,是否持久化磁盘缓存,当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名为cache名称,后缀名为index的文件,这个文件中存放了已经持久化在磁盘中的cache的index,找到后会把cache加载到内存,要想把cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法diskSpoolBufferSizeMB:           这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区diskExpiryThreadIntervalSeconds: 磁盘失效线程运行时间间隔,默认为120秒clearOnFlush:                    内存数量最大时是否清除--><!--defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则默认缓存策略--><defaultCache eternal="false" maxElementsInMemory="1000"overflowToDisk="true" diskPersistent="true"timeToIdleSeconds="0" timeToLiveSeconds="600"memoryStoreEvictionPolicy="LRU"/><cachename="myCache"eternal="false"maxElementsInMemory="200"overflowToDisk="false"diskPersistent="true"timeToIdleSeconds="0"timeToLiveSeconds="300"memoryStoreEvictionPolicy="LRU"/><cachename="myCache1"eternal="false"maxElementsInMemory="200"overflowToDisk="false"diskPersistent="true"timeToIdleSeconds="0"timeToLiveSeconds="10"memoryStoreEvictionPolicy="LRU"/>
</ehcache>

设置项目启动时使用缓存

@SpringBootApplication
@EnableCaching //开启缓存
public class Springboot01Application {public static void main(String[] args) {SpringApplication.run(Springboot01Application.class, args);}
}

application.yml 配置文件中读取 ehcache.xml 文件

spring:logging:config: classpath:logback-spring.xml# 可开启打印 sql 语句,方便测试level:com.hz.mapper: debug# 读取缓存配置文件cache:ehcache:config: classpath:ehcache.xml

使用注解

@Cacheable

@Cacheable 可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring 会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。

Spring 在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键,Spring 支持两种策略,默认策略和自定义策略。

注意:当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。

@Cacheable 注解的属性可以定义如下:

  • value:缓存名称,用于指定将方法返回值存储在哪个缓存中。可以是一个或多个缓存名称,当使用多个缓存时,需要用数组或列表的形式指定。
  • key:缓存键,用于指定缓存数据的键。默认情况下,Spring 会使用方法参数来生成键。
  • condition:满足该条件时才缓存方法的结果。可以使用 SpEL 表达式。
  • unless:满足该条件时方法的结果不进行缓存。可以使用 SpEL 表达式。
  • sync:如果设置为 true,则会在方法执行期间对缓存进行同步,避免多个线程同时执行该方法。
@Cacheable("myCache")//Cache是发生在ehcache.xml中myCache上的
public User find(Integer id) {return null;
}
@Cacheable({"cache1", "cache2"})//Cache是发生在ehcache.xml中cache1和cache2上的
public User find(Integer id) {return null;
}

value 属性是必须指定的,其表示当前方法的返回值是会被缓存在哪个 Cache 上的,对应 Cache 的名称。其可以是一个 Cache 也可以是多个 Cache。

key 属性是用来指定 Spring 缓存方法的返回结果时对应的 key 的。该属性支持 SpringEL 表达式。当没有指定该属性时,Spring 将使用默认策略生成 key。

自定义策略是指可以通过 Spring 的 EL 表达式来指定我们的 key。这里的 EL 表达式可以使用方法参数及它们对应的属性。使用方法参数时我们可以直接使用 #参数名#p参数index

下面是几个使用参数作为 key 的示例。

// #id表示参数id作为key
@Cacheable(value="myCache1", key="#id")
public User find(Integer id) {return null;
}
// #p0表示第一个参数作为key
@Cacheable(value="myCache1", key="#p0")
public User find(Integer id) {return null;
}
// #user.user_id表示对象user属性user_id作为key
@Cacheable(value="myCache1", key="#user.user_id")
public User find(User user) {return null;
}
// #p0.user_id表示参数位置
@Cacheable(value="myCache1", key="#p0.user_id")
public User find(User user) {return null;
}

除了上述使用方法参数作为 key 之外,Spring 还为我们提供了一个 root 对象可以用来生成 key。通过该 root 对象我们可以获取到以下信息。

属性名称描述示例
methodName当前方法名#root.methodName
method当前方法#root.method.name
target当前被调用的对象#root.target
targetClass当前被调用的对象的class#root.targetClass
args当前方法参数组成的数组#root.args[0]
caches当前被调用的方法使用的Cache#root.caches[0].name

当我们要使用 root 对象的属性作为 key 时我们也可以将 #root 省略,因为 Spring 默认使用的就是 root 对象的属性。如:

@Cacheable(value={"users", "xxx"}, key="caches[1].name")
public User find(User user) {return null;
}

condition 属性默认为空,表示将缓存所有的调用情形。其值是通过 SpringEL 表达式来指定的,当为 true 时表示进行缓存处理;当为 false 时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次。如下示例表示只有当 user 的 id 为偶数时才会进行缓存。

@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {System.out.println("find user by user " + user);return user;
}

@CachePut

在支持 Spring Cache 的环境下,对于使用 @Cacheable 标注的方法,Spring 在每次执行前都会检查 Cache 中是否存在相同 key 的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut 也可以声明一个方法支持缓存功能。

与 @Cacheable 不同的是使用 @CachePut 标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

@CachePut 也可以标注在类上和方法上;可指定的属性与 @Cacheable 一样。

@CachePut("users")//每次都会执行方法,并将结果存入指定缓存
public User find(Integer id) {return null;
}

@CacheEvict

@CacheEvict 是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict 可以指定的属性有 value、key、condition、allEntries 和beforeInvocation。其中 value、key 和 condition 的语义与 @Cacheable 对应的属性类似。

  • allEntries:在方法调用之后是否应该应用缓存清除。默认为 false。
  • beforeInvocation:是否在方法抛出异常时仍然清除缓存。默认为 false。
@CacheEvict(value="users", allEntries = true)
public void delete(Integer id) {System.out.println("delete user by id: " + id);
}
@CacheEvict(value="users", beforeInvocation = true)
public void delete(Integer id) {System.out.println("delete user by id: " + id);
}

@Caching

@Caching 注解可以让我们在一个方法或者类上同时指定多个 Spring Cache 相关的注解。其拥有三个属性: cacheable、put 和 evict,分别用于指定 @Cacheable、@CachePut 和 @CacheEvict。

@Caching(cacheable = @Cacheable("users"), evict = { @CacheEvict("cache2"),@CacheEvict(value = "cache3", allEntries = true) })
public User find(Integer id) {returnnull;
}

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

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

相关文章

【STM32+QT项目】基于STM32与QT的智慧粮仓环境监测与管理系统设计(完整工程资料源码)

视频演示: 基于STM32与QT的智慧粮仓环境监测与管理系统设计 目录: 目录 视频演示: 目录: 前言:

Backend - C# 操作数据库 DB(ADO.NET、LINQ to SQL、EF)

目录 一、ADO.NET&#xff08;传统&#xff09; 二、LINQ to SQL&#xff08;已过时&#xff09; 三、EF&#xff08;推荐&#xff09; 常见的操作数据库的方法&#xff1a;有三种&#xff0c;分别是 ADO.NET、LINQ to SQL、EF 一、ADO.NET&#xff08;传统&#xff09; ADO.NE…

机器学习周报-ModernTCN文献阅读

文章目录 摘要Abstract 0 提升有效感受野&#xff08;ERF&#xff09;1 相关知识1.1 标准卷积1.2 深度分离卷积&#xff08;Depthwise Convolution&#xff0c;DWConv&#xff09;1.3 逐点卷积&#xff08;Pointwise Convolution&#xff0c;PWConv&#xff09;1.4 组卷积(Grou…

《OpenCV计算机视觉实战项目》——银行卡号识别

文章目录 项目任务及要求项目实现思路项目实现及代码导入模块设置参数对模版图像中数字的定位处理银行卡的图像处理读取输入图像&#xff0c;预处理找到数字边框使用模版匹配&#xff0c;计算匹配得分 画出并打印结果 项目任务及要求 任务书&#xff1a; 要为某家银行设计一套…

Yolo11改进:注意力改进|Block改进|ESSAformer,用于高光谱图像超分辨率的高效Transformer|即插即用

摘要 一、论文介绍 高光谱图像超分辨率的重要性:高光谱成像技术通过密集采样光谱特征,为材料区分提供丰富的光谱和空间结构信息,广泛应用于各领域。高光谱图像超分辨率(HSI-SR)旨在从低分辨率HSI生成高分辨率HSI。传统方法的局限性:传统方法依赖手工制作的先验,如低秩近…

概要性了解Linux的总线设备驱动

引言 假如我们的板子上有很多LED&#xff0c;有时候需要操作这个LED&#xff0c;有时候需要操作另一个LED&#xff0c;我们希望代码可以清晰地组织在一起&#xff0c;方便扩展&#xff0c;同时自动为这些具体的设备生成对应的设备文件以供用户空间使用。 在Linux中&#xff0…

Swift语言的正则表达式

Swift语言的正则表达式 正则表达式是一种用于匹配字符串的强大工具&#xff0c;它可以帮助开发者在文本处理中高效地搜索和操作字符串。在Swift语言中&#xff0c;正则表达式的支持是通过Foundation框架提供的。本文将全面介绍Swift中的正则表达式&#xff0c;从基础知识到进阶…

【LeetCode: 560. 和为 K 的子数组 + 前缀和 + 哈希表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

Tableau数据可视化与仪表盘搭建-可视化原则及BI仪表盘搭建

目录 可视化原则 BI仪表盘搭建 仪表盘搭建原则 明确仪表盘主题 仪表盘主题拆解 开发设计工作表 经营情况总览&#xff1a;突出显示的文字 经营数据详情&#xff1a;表格 每日营收数据&#xff1a;多轴折线图 每日流量数据&#xff1a;双轴组合图 新老客占比&#xf…

vue2日历组件

这个代码可以直接运行&#xff0c;未防止有组件库没安装&#xff0c;将组件库的代码&#xff0c;转成文字了 vue页面 <template><div class"about"><div style"height: 450px; width: 400px"><div style"height: 100%; overflo…

交响曲-24-3-单细胞CNV分析及聚类

CNV概述 小于1kb是常见的插入、移位、缺失等的变异 人体内包含<10% 的正常CNV&#xff0c;我们的染色体数是两倍体&#xff0c;正常情况下&#xff0c;只有一条染色体表达&#xff0c;另一条沉默&#xff0c;当表达的那条染色体发生CNV之后&#xff0c;表达数量就会成倍增加…

UDP -- 简易聊天室

目录 gitee&#xff08;内有详细代码&#xff09; 图解 MessageRoute.hpp UdpClient.hpp UdpServer.hpp Main.hpp 运行结果&#xff08;本地通信&#xff09; 如何分开对话显示&#xff1f; gitee&#xff08;内有详细代码&#xff09; chat_room zihuixie/Linux_Lear…

python对redis的增删查改

python对redis的增删查改 安装 redis-py 库连接 Redis 服务器增1. 字符串&#xff08;String&#xff09;2. 列表&#xff08;List&#xff09;3. 哈希&#xff08;Hash&#xff09;4. 集合&#xff08;Set&#xff09;5. 有序集合&#xff08;Sorted Set&#xff09; 删1. 删除…

电影动画shader解析与实现

着色器代码解析 大家好&#xff01;我是 [数擎AI]&#xff0c;一位热爱探索新技术的前端开发者&#xff0c;在这里分享前端和Web3D、AI技术的干货与实战经验。如果你对技术有热情&#xff0c;欢迎关注我的文章&#xff0c;我们一起成长、进步&#xff01; 开发领域&#xff1a;…

代码随想录算法【Day11】

150. 逆波兰表达式求值 class Solution { public:int evalRPN(vector<string>& tokens) {// 力扣修改了后台测试数据&#xff0c;需要用longlongstack<long long> st; for (int i 0; i < tokens.size(); i) {if (tokens[i] "" || tokens[i] &…

让Qt 具有多选文件夹和记忆上一次打开位置的文件对话框

最近要做一个可以多选文件夹的功能&#xff0c;在网上查阅了多个资料&#xff0c;发现github有一段代码可以实现该功能&#xff0c;于是将其收入进行改造。另外qt自带的 getExistingDirectory 和 getOpenFileNames 不具有记忆上一次打开的文件夹位置。要实现多选文件夹和记忆上…

【杂谈】-50+个生成式人工智能面试问题(一)

50个生成式人工智能面试问题 文章目录 50个生成式人工智能面试问题1、生成式人工智能面试问题与神经网络相关Q1. 什么是Transformers&#xff1f;Q2. 什么是注意力机制&#xff1f;有哪些类型的注意力机制&#xff1f;Q3. 为什么Transformer比RNN架构更好&#xff1f;Q4. Trans…

【FlutterDart】 拖动边界线改变列宽类似 vscode 那种拖动改变编辑框窗口大小(11 /100)

【Flutter&Dart】 拖动改变 widget 的窗口尺寸大小GestureDetector&#xff5e;简单实现&#xff08;10 /100&#xff09; 【Flutter&Dart】 拖动边界线改变列宽并且有边界高亮和鼠标效果&#xff08;12 /100&#xff09; 上效果&#xff1a; 这个在知乎里找到的效果&…

原型模式详解与实践

在软件开发的奇妙世界里&#xff0c;我们常常面临重复创建相似对象的任务。如果每次创建都要从头开始设置各种属性和状态&#xff0c;不仅繁琐&#xff0c;还可能降低效率。原型模式就像一位神奇的魔法师&#xff0c;为我们提供了一种通过复制现有对象来创建新对象的优雅方式。…

比较procfs 、 sysctl和Netlink

procfs 文件系统和 sysctl 的使用: procfs 文件系统(/proc) procfs 文件系统是 Linux 内核向用户空间暴露内核数据结构以及配置信息的一种方式。`procfs` 的挂载点是 /proc 目录,这个目录中的文件和目录呈现内核的运行状况和配置信息。通过读写这些文件,可以查看和控制内…