SpringBoot使用缓存

news2024/11/15 5:22:49

目录

简介

Spring 的缓存主要有如下几个注解

红色标注的注解为最常用的注解,必须熟练掌握

 @Cacheable/@CachePut/@CacheEvict 主要的参数

SpEL 提供的运算符

实现步骤

补充

注意

整合 EHCACHE


简介

 

Spring 框架已经具备了缓存机制,虽然我们可以使用 Redis 等作为缓存处理机制,不过对于非常零碎的数据交互其实使用 Spring 的缓存机制反而显得简单;而且我们可以将 Spring 的缓存机制融合 Redis 和 关系型数据库建立一个完备的数据处理方案,相当于实现了 3 级缓存,将非常有助于超大型系统的数据交互压力

Spring 的缓存主要有如下几个注解

红色标注的注解为最常用的注解,必须熟练掌握

 @Cacheable/@CachePut/@CacheEvict 主要的参数

SpEL上下文数据

Spring 为我们提供了一个 root 对象可以用来生成 key,通过该 root 对象我们可以获取到以下信息

SpEL 提供的运算符

 

注意

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

@Cacheable(key="targetClass + methodName +#p0")

(2) 使用方法参数时我们可以直接使用“#参数名”或者“#p参数 index ”, 如:

@Cacheable(value="users", key="#id")@Cacheable(value="users", key="#p0")

实现步骤

1 因为我们使用了 SpringBoot 框架,而 SpringBoot 框架已经包含了缓存所依赖的包,所以直接使用上面的注解即可,不用添加如下依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

2. 在 SpringBoot 项目的启动类上添加 @EnableCaching 注解,表示打开缓存驱动

@SpringBootApplication
@EnableCaching
public class App {    
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

3. 新建 CacheService.class,添加如下 3 个方法

@Service
public class CacheService {
    // 如果缓存中没有要查询的值, 将执行方法中的代码, 并将返回值更新到缓存
    // 如果缓存中有要查询的值, 将不会执行方法中的代码, 而是直接从缓存返回值
    @Cacheable(cacheNames = {"myCache"}, key = "#root.targetClass")
    public String get() {
        System.out.println(new Date() + " --> 没有从缓存取值");
        return“ Ramos”;
    }

    // 该注解将会向缓存中 添加/更新 新的值
    // 与 @Cacheable 不同的是, 如下方法中的代码都会执行
    @CachePut(cacheNames = {"myCache"}, key = "#root.targetClass")
    public String put(String value) {
        System.out.println(new Date() + " 添加了 value --> " + value);
        return value;
    }

    // 该注解将会把缓存中的值删除掉
    // 与 @Cacheable 不同的是, 如下方法中的代码都会执行
    @CacheEvict(cacheNames = {"myCache"}, key = "#root.targetClass")
    public void delete(String key) {
        System.out.println(new Date() + " 删除了 value ");
    }
}

4. 在 application.properties 配置文件中添加如下配置

# 指定使用缓存管理器
spring.cache.type=simple
# 定义全局缓存名
spring.cache.cache-names=xxx,xxx...
# 指定缓存管理器的配置文件(非必须, 对于某些有配置文件的缓存插件才需要配置)
#spring.cache.config=classpath:xxx.xml

如果没有添加上面的注解,会报错:Cannot find cache named xxx; cache.type 可选值如下:

GENERIC,
JCACHE,
EHCACHE,
HAZELCAST,
INFINISPAN,
COUCHBASE,
REDIS,
CAFFEINE,
SIMPLE,
NONE;

补充

1. @Cacheable 注解,主要有如下 2 个作用:

(1) 当缓存中没有要的值的时候,会执行该注解下的方法,并将该方法的返回值保存到缓存

(2) 当缓存中有要的值的时候,不会执行注解下的方法,将直接返回缓存中的值

2. @Cacheput 注解:主要是更新缓存中的值,不返回值,有则覆盖,没有则添加

3. @CacheEvict 注解:将缓存中的值删除,注意

(1) 该注解的 allEntries 属性,当设置为 true 的时候,将会忽略所有的 key,清除所有的缓存

(2) 该注解 beforeInvocation 属性, 清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作;使用 beforeInvocation 可以改变触发清除操作的时间,当指定该属性值为 true 时,Spring 会在调用该方法之前清除缓存中的指定元素

4. 以上注解中的 cacheNames 属性可以理解为 数据库的库,而 key 属性可以理解为 数据库的表;
如果一个方法上添加的是@Cacheable (cacheNames="a", key="1"); 而另一个方法上添加的@CacheEvict(cacheNames="a", key="2"); 他们的 cacheNames(相当于数据库)相同;但是 key(相当于表) 不同,当执行了清理缓存的方法后,key=“1” 的缓存依然还在;cacheNames 属性和 value 属性等效,参数都是 String 数组,不过为了避免误解(该 value 不是往缓存里存的那个 value,千万不要混淆!!!!!!!!!!),建议还是使用 cacheNames 属性

5. @CacheConfig 注解的使用
从实现步骤 3 中可以看到,每个方法上的注解都有相同的属性,虽然注解不一样,但是 cacheNames 属性和 key 属性是一样的,那么如果有很多个方法,且他们的参数都一样的话,代码看起来就会显得很冗余,这个时候就可以使用 @CacheConfig 注解来解决这个问题;经过修改后的 CacheService.class 代码如下

@Service
@CacheConfig(cacheNames={"myCache"}, keyGenerator="cacheKeyGenerator")
public class CacheService {
    @Cacheable
    public String save() {
        System.out.println(new Date() + " --> 没有从缓存取值");
        return "Ramos";
    } 
}

注意

@CacheConfig 注解,该注解的 cacheNames 属性自然是为所有的缓存注解标明缓存名称(可理解为数据库名),keyGenerator 属性(非必需)表示所有缓存的 key 的生成策略,需要为其注入一个 Bean,且该 Bean 要实现 KeyGenerator 接口,并要重写 generate 方法;如下是我们自定义的 CacheKeyGenerator 类,注意和 keyGenerator 属性值对比

@Component
// 自定义缓存 key 的生成策略
public class CacheKeyGenerator implements KeyGenerator {
    // 将目标类的类名作为 key 值
    @Override
    public Object generate(Object target, Method method, Object... params) {
        return target.getClass().getName();
    }
}

6. 组合@Caching

有时候我们可能组合多个Cache注解使用,此时就需要@Caching组合多个注解标签了,如下

@Caching(cacheable = {
    @Cacheable(value = "emp",key = "#p0"),
        ...
},
put = {
    @CachePut(value = "emp",key = "#p0"),
        ...
},evict = {
    @CacheEvict(value = "emp",key = "#p0"),
        ....
})
public User save(User user) {
    ....
}

整合 EHCACHE

Ehcache 是一种广泛使用的开源 Java 分布式缓存,主要面向通用缓存,Java EE 和轻量级容器;它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个 gzip 缓存 servlet 过滤器,支持 REST和 SOAP API 等特点;其实对于一般的使用来说,上面介绍的缓存用法已经足够,Ehcache 最大的优点是可以将缓存中的内容写入到本地磁盘中,并可配置缓存过期时间

1. 首先需要添加如下 3 个依赖,缺一不可

<!-- ehcache 缓存 -->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
<!--开启缓存支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
</dependency>

2. 在 src/main/resource 目录下创建 ehcache.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <!-- 磁盘存储:
	 将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存 
	 path:指定在硬盘上存储对象的路径 path可以配置的目录有
	 user.home(用户的家目录)
	 user.dir(用户当前的工作目录)
	 java.io.tmpdir(默认的临时目录)
	 ehcache.disk.store.dir(ehcache的配置目录)
	 绝对路径(如:d:\\ehcache) 查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir"); 
	-->
	<!-- <diskStore path="java.io.tmpdir" /> -->
	<diskStore path="c:/cache" />

	<!-- defaultCache: 默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理
		 maxElementsInMemory: 设置了缓存的上限,最多存储多少个记录对象 
		 eternal: 代表对象是否永不过期 (指定true则下面两项配置需为0无限期) 
		 timeToIdleSeconds: 最大的发呆时间 /秒 
		 timeToLiveSeconds: 最大的存活时间 /秒
		 overflowToDisk: 是否允许对象被写入到磁盘 
		 说明: 下列配置自缓存建立起10秒有效 
		       在有效的10内,如果连续10未访问缓存,则缓存失效 
		       就算有访问,也只会存活10秒 
	-->
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="10" timeToLiveSeconds="10" overflowToDisk="false"/>

<cache name="myCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="10" timeToLiveSeconds="10" overflowToDisk="true"/>

</ehcache>

3. 在 application.properties 配置文件中添加如下配置

# 指定缓存配置文件(也可以使用 spring.cache.ecache.config=xxx)
spring.cache.jcache.config = classpath:ehcache.xml

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

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

相关文章

Locust框架从0到1入门

Locust介绍 Locust是使用Python语言编写实现的开源性能测试工具&#xff0c;可以用来测试Web应用程序、API、数据库等各种应用程序的性能&#xff0c;使用起来简洁、轻量、高效&#xff0c;并发机制基于gevent协程&#xff0c;可以实现单机模拟生成较高的并发压力。中文意为&a…

【目标检测】正负样本分配策略

YOLO v3 目标的中心点在哪个网格内由该网格负责预测该目标&#xff0c;max-iou matching策略 &#xff08;1&#xff09;计算GT的中心点在哪个网格&#xff1b; &#xff08;2&#xff09;计算该网格内的所有anchor与GT的IOU&#xff0c;选择IOU最大的anchor负责预测该GT&…

嵌入安防监控项目——BOA服务器的移植

目录 一、源码下载 1.1 boa简介&#xff1a; 1.2BOA再项目中的使用 二、解压源码&#xff1a; 三、进入源码目录下的src目录&#xff1a; 四、make 编译源码&#xff1a; 五、建立安装目录 六、返回boa的顶层目录 --- 修改配置文件 七、建立测试页面 八、查看/boa目…

43-Golang中的goroutine!!!

Golang中的goroutine进程和线程说明并发和并行并发并行Go协程和Go主线程案例小结goroutine的调度机制MPG模式基本介绍MPG模式运行的状态1MPG模式运行的状态2设置GOlang运行的CPU数不同 goroutine之间如何通讯使用全局变量加锁同步改进程序进程和线程说明 1.进程就是程序在操作…

robosuite添加无碰撞的模型

1 前言 最近在使用robosuite时,需要在仿真环境中可视化物体的目标位置,从而方便观察训练情况,可视化的物体有以下要求: 形状尺寸与操作的物体一样半透明只有visual,不与场景其他物体有碰撞可以在每次step后设置位置,且固定在设定的位置,不受重力影响 2 方法 找了半天,最终确…

javaWeb核心04-CookieSession

文章目录会话技术1&#xff0c;会话跟踪技术的概述2&#xff0c;Cookie2.1 Cookie的基本使用2.2 Cookie的原理分析2.3 Cookie的使用细节2.3.1 Cookie的存活时间2.3.2 Cookie存储中文3&#xff0c;Session3.1 Session的基本使用3.2 Session的原理分析3.3 Session的使用细节3.3.1…

2018年MathorCup数学建模D题公交移动支付问题的评估方案解题全过程文档及程序

2018年第八届MathorCup高校数学建模挑战赛 D题 公交移动支付问题的评估方案 原题再现&#xff1a; 随着智能手机的普及和移动支付技术的提高,越来越多的支付手段可以转移到手机端。现有的现金缴费和实体公交卡刷卡的付费方式存在缺点&#xff0c;如公交卡在使用过程中存在着充…

Landsat8中*_MTL.txt文件详解

01 什么是*_MTL.txt文件&#xff1f;所有的Landsat8 1级数据产品中均包含MTL.txt(Metadata File)文件。Landsat MTL文件包含对数据的系统搜索和归档分类有益的信息。该文件还包含关于数据处理和恶对增强陆地卫星数据有重要价值的信息&#xff08;例如转换为反射率和辐射亮度&am…

Java 集合进阶(二)

文章目录一、Set1. 概述2. 哈希值3. 元素唯一性4. 哈希表5. 遍历学生对象6. LinkedHashSet7. TreeSet7.1 自然排序7.2 比较器排序8. 不重复的随机数二、泛型1. 概述2. 泛型类3. 泛型方法4. 泛型接口5. 类型通配符6. 可变参数7. 可变参数的使用一、Set 1. 概述 Set 集合特点&am…

AI领域通识

人工智能的架构&#xff1a;通常来说&#xff0c;人工智能架构分为四层&#xff1a;最底层的基础层一般由软硬件设施以及数据服务组成。软件设施主要包括智能云平台和大数据平台&#xff0c;比如国外的谷歌大数据平台和国内的百度智能云平台等&#xff1b;硬件设施主要包括CPU硬…

讨论基于最新的(v5或v6版本)UXP插件开发的开发框架的选择问题

看过我的上两篇文章后&#xff0c;相信你对UXP的开发环境已经有一定了解了&#xff0c;然后这里讨论一个问题&#xff0c;UXP的开发可以基于纯htmlcssjs、vue框架、react框架、svelte框架&#xff0c;就是到底用哪种方式开发更好了&#xff1f;一般情况是用自己最熟悉的或者是使…

使用vue脚手架创建vue项目

大家好&#xff0c;这里是 一口八宝周 &#x1f44f;欢迎来到我的博客 ❤️一起交流学习文章中有需要改进的地方请大佬们多多指点 谢谢 &#x1f64f;使用脚手架创建vue项目步骤&#xff1a;切换淘宝镜像npm config set registry https://registry.npm.taobao.org安装脚手架npm…

算法拾遗二十七之窗口最大值或最小值的更新结构

算法拾遗二十七之窗口最大值或最小值的更新结构滑动窗口题目一题目二题目三题目四滑动窗口 第一种&#xff1a;R&#xff0c;R右动&#xff0c;数会从右侧进窗口 第二种&#xff1a;L&#xff0c;L右动&#xff0c;数从左侧出窗口 题目一 arr是N&#xff0c;窗口大小为W&…

C++ linux下获取时间戳 秒、微妙、纳秒

1.例子#include <iostream>#include <sys/time.h>#include <cstdlib>#include <cstdio>#include <ctime>#include <cmath>#include <unistd.h>usingnamespace std;time_t clocktime(){time_t t time(NULL);std::cout << &quo…

聚势合力,电巢与SDIA协会“战略合作签约仪式”圆满落成

前言&#xff1a; 2023年03月02日下午&#xff0c;电巢科技与深圳市平板显示行业协会齐聚深圳南山电巢XR演播厅&#xff0c;共同举办了隆重的战略合作签约仪式。 双方就数字化建设、品牌赋能、人才培养、技术创新等企业服务深入合作上达成一致&#xff0c;合力为产业赋能&…

【OJ比赛日历】快周末了,不来一场比赛吗? #03.11-03.17 #12场

CompHub 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号同时会推送最新的比赛消息&#xff0c;欢迎关注&#xff01;更多比赛信息见 CompHub主页 或 点击文末阅读原文以下信息仅供参考&#xff0c;以比赛官网为准目录2023-03-11&…

netty-websocket 鉴权token及统一请求和响应头(鉴权控制器)

自己想法和实现&#xff0c;如果有说错的或者有更好的简单的实现方式可以私信交流一下(主要是实现握手时鉴权) 需求实现 握手鉴权是基于前台请求头 Sec-WebSocket-Protocol的本身socket并没有提供自定义请求头&#xff0c;只能自定义 Sec-WebSocket-Protocol的自协议 问题描述…

你几乎不知道的浏览器内置对象/事件/ajax

浏览器内置对象/事件/ajax 浏览器是⼀个 JS 的运⾏时环境&#xff0c;它基于 JS 解析器的同时&#xff0c;增加了许多环境相关的内容。⽤⼀张图表示各个运⾏环境和 JS 解析器的关系如下&#xff1a; 我们把常⻅的&#xff0c;能够⽤ JS 这⻔语⾔控制的内容称为⼀个 JS 的运⾏环…

Leetcode—环形链表

前言&#xff1a;给定一个链表&#xff0c;判断是否为循环链表并找环形链表的入口点 首先我们需要知道什么是双向循环链表&#xff0c;具体如下图所示。 对于链表&#xff0c;我们如何去判断链表是循环链表呢&#xff1f;又寻找入环点呢&#xff1f;我们可以利用快慢指针的方法…

Meta CTO:Quest 2生命周期或比预期更久

前不久&#xff0c;Meta未来4年路线图遭曝光&#xff0c;泄露了该公司正在筹备中的一些AR/VR原型。除此之外&#xff0c;还有消息称Quest Pro或因销量不佳&#xff0c;而不再迭代。毫无疑问&#xff0c;Meta的一举一动持续受到行业关注&#xff0c;而面对最近的爆料&#xff0c…