SpringCache缓存介绍
1.为什么需要缓存
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果:
使用缓存是一个很“高性价比”的性能优化方式,尤其是对于有大量重复查询的程序来说。通常来说,在WEB后端应用程序来说,
耗时比较大的往往有两个地方:
1、查数据库;
2、调用其它服务的API(因为其它服务最终也要去做查数据库等耗时操作);
重复查询也有两种:
1、我们在应用程序中代码写得不好,写的for循环,可能每次循环都用重复的参数去查询了。
2、大量的相同或相似请求造成的。比如资讯网站首页的文章列表、电商网站首页的商品列表、微博等社交媒体热搜的文章等等,当大量的用户都去请求同样的接口,同样的数据,如果每次都去查数据库,那对数据库来说是一个不可承受的压力。所以我们通常会把高频的查询进行缓存,我们称它为“热点”。
2.SpringCache概述
前面提到了缓存有诸多的好处,于是大家就摩拳擦掌准备给自己的应用加上缓存的功能。但是网上一搜却发现缓存的框架太多了,各有各的优势,比如Redis[中央缓存-远程缓存]、Memcached、Guava、Caffeine[本地缓存]等等。
如果我们的程序想要使用缓存,就要与这些框架耦合。聪明的架构师已经在利用接口来降低耦合了,利用面向对象的抽象和多态的特性,做到业务代码与具体的框架分离。
但我们仍然需要显式地在代码中去调用与缓存有关的接口和方法,在合适的时候插入数据到缓存里,在合适的时候从缓存中读取数据。想一想**「AOP」**的适用场景,这不就是天生就应该AOP去做的吗?
自Spring 3.1起,提供了类似于 @Transactional 注解事务的注解Cache支持,且提供了Cache抽象,在此之前一般通过AOP实现。
使用Spring Cache的好处:
- 提供基本的Cache抽象,方便切换各种底层Cache;
- 通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;
- 提供事务回滚时也自动回滚缓存;
- 支持比较复杂的缓存逻辑;
2.1SpringCache概述及核心配置
Spring Cache就是一个缓存框架。它利用了AOP(将缓存逻辑与服务逻辑解耦),实现了基于注解的缓存功能(声明式缓存),并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,只需要简单地加一个注解,就能实现缓存功能了。而且Spring Cache也提供了很多默认的配置,用户可以快速将缓存集成到项目中;
接下来,我们以一个很小的例子给大家讲解SpringCache的快速使用;
2.2. SpringCache环境准备
导入:day12\SpringCache缓存专题\代码\springboot-cache项目代码;
核心步骤如下:
2.2.1 缓存依赖导入
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.2.2 环境配置
#数据库配置
spring:redis:host: 192.168.200.130 # Redis服务器地址database: 1 # Redis数据库索引(默认为0)port: 6379 # Redis服务器连接端口
# password: ld123456 # Redis服务器连接密码(默认为空)
2.2.3 缓存配置类定义
SpringCache抽象出公共的缓存接口,同时面向用户屏蔽了底层实现细节,用户可通过配置缓存管理器来实现缓存方案的替换:
我们当前以Redis作为SpringCache缓存底层实现为例展开讲解。
/*** @author itheima* code 自定义redis序列化配置类*/
@Configuration
public class RedisCacheConfig {/*** 配置 cacheManager 代替默认的cacheManager (缓存管理器)* @param factory RedisConnectionFactory* @return CacheManager*/@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisSerializer<String> redisSerializer = new StringRedisSerializer();Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);//仅仅序列化对象的属性,且属性不可为final修饰objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);serializer.setObjectMapper(objectMapper);// 配置key value序列化RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))//关闭控制存储.disableCachingNullValues()//修改前缀与key的间隔符号,默认是::.computePrefixWith(cacheName->cacheName+":");//设置特有的Redis配置Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();//定制化的Cache 设置过期时间 eg:以role:开头的缓存存活时间为10scacheConfigurations.put("role",customRedisCacheConfiguration(config,Duration.ofSeconds(10)));cacheConfigurations.put("stock",customRedisCacheConfiguration(config,Duration.ofSeconds(3000)));cacheConfigurations.put("market",customRedisCacheConfiguration(config,Duration.ofSeconds(300)));//构建redis缓存管理器RedisCacheManager cacheManager = RedisCacheManager.builder(factory)//Cache事务支持.transactionAware().withInitialCacheConfigurations(cacheConfigurations).cacheDefaults(config).build();//设置过期时间return cacheManager;}/*** 设置RedisConfiguration配置* @param config* @param ttl* @return*/public RedisCacheConfiguration customRedisCacheConfiguration(RedisCacheConfiguration config, Duration ttl) {//设置缓存缺省超时时间return config.entryTtl(ttl);}
}
2.3 SpringCache注解详解
2.3.1 @Cacheable注解
如果缓存中没有:查询数据库,存储缓存,返回结果,
如果缓存中有:直接返回结果
作用:可以用来进行缓存的写入,将结果存储在缓存中,以便于在后续调用的时候可以直接返回缓存中的值,而不必再执行实际的方法。 最简单的使用方式,注解名称=缓存名称,使用例子如下:
示例代码:
@Service
@CacheConfig(cacheNames = "role")//提取缓存的前缀配置
public class RoleServiceImpl implements IRoleService {@Autowiredprivate RoleMapper roleMapper;/*** <p>* 几个属性:* a)cacheNames/value:指定缓存组件的名字* cacheNames = {"role"}可以使用多个参数,是数组的形式,可以指定多个缓存* b)key:缓存数据使用的key,可以用他来指定。默认是使用方法参数的值* 编写SpEl: #id #a0,#po,#argrs[0] "0"代表参数的索引* #result 方法执行后的返回值* #root.methodName 方法名* key = "#root.methodName+'['+#id+']'"* e)condition:指定符合缓存的条件* condition = "#id>0 and #root.methodName eq 'aaa'" 可以多条件判断* f)unless: 否定缓存,当unless的条件为true,方法结果不会被缓存,可以获取结果进行判断* unless = "#result==null",结果为null,就不缓存*/@Override//@Cacheable(cacheNames = "role", key = "#id",condition = "#id>0",unless = "#result==null")@Cacheable(key = "#id",condition = "#id>0",unless = "#result==null")public Role findById(Integer id) {return roleMapper.selectByPrimaryKey(id);}@Cacheable(key ="#root.method.getName()")//直接引用mehtodname异常@Overridepublic R findAllRole() {List<Role> roleList = roleMapper.findAll();return R.ok(roleList);}
}
2.3.2 @CacheEvict注解
@CacheEvict:删除缓存的注解,这对删除旧的数据和无用的数据是非常有用的。这里还多了一个参数(allEntries),设置allEntries=true时,可以对整个条目进行批量删除
示例代码:
/*** .@CacheEvict 缓存清除* key:指定要清除的数据*/@Override@CacheEvict(key = "#id")public Integer delete(Integer id) {return roleMapper.deleteByPrimaryKey(id);}
2.3.3 @CachePut注解
@CachePut:当需要更新缓存而不干扰方法的运行时 ,可以使用该注解。也就是说,始终执行该方法,并将结果放入缓存
本质上说,如果存在对应的缓存,则更新覆盖,不存在则添加;
示例代码:
/*** .@CachePut既调用方法、又更新数据,达到同步更新缓存* <p>* 运行时机:* 1、先调用目标方法 ★★★* 2、将目标方法的结果缓存起来★★★* 条件:存取Id的key要保持一致* key = "#role.id" 传入员工的Id* key = "#result.id" 使用返回员工的Id* 注意: @Cacheable不能使用#result* 因为 @Cacheable在目标方法执行之前需要得到这个key,所以不能用#result*/
@Override
@CachePut(key = "#result.id")//更新或者添加缓存---》有则更新,无则添加
public Role update(Role role) {roleMapper.updateByPrimaryKey(role);return role;
}
2.3.4 @Caching注释
在使用缓存的时候,有可能会同时进行更新和删除,会出现同时使用多个注解的情况.而@Caching可以实现,对于复杂的缓存策略,我们可借助SpEL实现;
Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档:
其它:如果表达式想直接引用一个常量值,那么需要 key=“‘xxxx’”
示例代码:
/*** .@Caching 定义复杂缓存规则*/@Override@Caching(cacheable = {@Cacheable(key = "#role.rolename")},put = {@CachePut(key = "#role.id"),@CachePut(key = "#role.rolecode")},evict = {@CacheEvict(key = "8")})public R add(Role role) {
// role.setId(null);try {roleMapper.insert(role);} catch (Exception e) {return R.error();}return R.ok(role.getId());}
2.3.5 注解小结
对于缓存声明,spring的缓存提供了一组java注解:
- @Cacheable
- 功能:触发缓存写入,如果缓存中没有,查询数据库,存储缓存,返回结果,如果缓存中有,直接返回结果
- 应用:查询数据库方法,且查询的数据时热点数据
- @CacheEvict
- 功能:触发缓存清除
- 应用:删除或修改数据库方法
- @CachePut
- 功能:缓存写入(不会影响到方法的运行)。有则更新,无则添加
- 应用:新增到数据库方法
- @Caching
- 功能:重新组合要应用于方法的多个缓存操作
- 应用:上面的注解的组合使用
- @CacheConfig(cacheNames = “xxx”)
- 功能:可以提取公共的缓存key的前缀,一般是业务的前缀
- 应用:作用在类之上
相关文章:

SpringCache缓存介绍
1.为什么需要缓存 前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果: 使用缓存是一个很…...

python实战(一)——iris鸢尾花数据集分类
一、任务背景 本文是python实战系列专栏的第一篇文章,我们将从分类开始由浅入深逐步学习如何使用python完成常规的机器学习/深度学习任务。iris数据集是经典的机器学习入门数据集,许多分类任务教程都会以这个数据集作为示例,它的数据量是150条…...

k8s-对命名空间资源配额
对k8s命名空间限制的方法有很多种,今天来演示一下很常用的一种 用的k8s对象就是ResourceQuota 一:创建命名空间 kubectl create ns test #namespace命名空间可以简写成ns 二: 对命名空间进行限制 创建resourcequota vim resourcequ…...

Failed to connect to github.com port 443
git push无法连接443端口 **问题1****方法一:取消代理设置**git命令 其他解决方案1. **设置 Git 使用 HTTP 而不是 HTTPS**2. **检查证书**3. **配置 Git 忽略 SSL 验证(不推荐)**4. **检查代理设置** 问题1 Failed to connect to github.com…...

【设计模式系列】简单工厂模式
一、什么是简单工厂模式 简单工厂模式(Simple Factory Pattern)是一种设计模式,其中包含一个工厂类,根据传入的参数不同,返回不同类的实例。这个工厂类封装了对象的创建逻辑,使得客户端代码可以从直接创建…...

给定一个正整数n随机生成n个字节即生成2n个十六进制数将其组成字符串返回secrets.token_hex(n)
【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 给定一个正整数n 随机生成n个字节 即生成2n个十六进制数 将其组成字符串返回 secrets.token_hex(n) [太阳]选择题 根据题目代码,执行的结果错误的是? import secrets …...

[Gtk] 工程
MediaPlayer 可执行文件工程 结构 . ├── BUILD ├── ButtonHelper.cpp ├── ButtonHelper.h ├── CMakeLists.txt ├── DrawingAreaHelper.cpp ├── DrawingAreaHelper.h ├── layout.ui └── main.cpp CMakeLists.txt # 1) cmake basic cmake_minimum_r…...

基于Multisim的汽车尾灯控制电路设计与仿真
假设汽车尾部左右量测各有3个指示灯(用发光二极管模拟)1. 汽车正常运行时指示灯全灭;2.右转弯时,右侧3个指示灯按右循环顺序点亮;.3. 左转弯时,左侧3个指示灯按左循环顺序点亮;4.临时刹车时所有…...

Leetcode 3326. Minimum Division Operations to Make Array Non Decreasing
Leetcode 3326. Minimum Division Operations to Make Array Non Decreasing 1. 解题思路2. 代码实现 题目链接:3326. Minimum Division Operations to Make Array Non Decreasing 1. 解题思路 这一题的话就是要看出来题中给出的operation的本质事实上就是将任意…...

redo文件误删除后通过逻辑备份进行恢复
问题描述 开发同事让在一个服务器上查找下先前库的备份文件是否存在,如果存在进行下恢复。翻了服务器发现备份文件存在,多愁了一眼竟翻到了该备份文件于2024.6.17日恢复过的日志,赶紧和开发沟通说2024.6.17号已经恢复过了为啥还要恢复&#x…...

7805的输出电压如何调整?
7805稳压集成电路的输出电压通常是固定的,标称为5V。然而,在实际应用中,可以通过一些方法调整其输出电压,尽管这些调整方法可能会使电路变得更加复杂或需要额外的元件。以下是几种可能的调整方法: 1. 使用不同型号的稳…...

git命令使用一览【自用】
git常见操作: git initgit remote add master【分支名字】 gitgits.xxxxx【仓库中获取的ssh链接或者http协议的链接】检查远程仓库是否链接成功。 git remote -v出现以下画面就可以git pull,git push了...

MES系列-报表和分析
MES系列-报表和分析 MES系列文章目录 ISA-95制造业中企业和控制系统的集成的国际标准-(1) ISA-95制造业中企业和控制系统的集成的国际标准-(2) ISA-95制造业中企业和控制系统的集成的国际标准-(3) ISA-95制造业中企业和控制系统的集成的国际标准-(4) ISA-95制造业中企业和控制…...

如何在分布式环境中实现高可靠性分布式锁
目录 一、简单了解分布式锁 (一)分布式锁:应对分布式环境的同步挑战 (二)分布式锁的实现方式 (三)分布式锁的使用场景 (四)分布式锁需满足的特点 二、Redis 实现分…...

Vue基础(4)
自定义指令 除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。在vue中使用directive来创建自定义指令 钩子函数 指令定义函数提供了几个钩子函数(可选): bind: 只调用一次,指令第一次绑定到元素时调用&…...

Redis高阶篇之Redis单线程与多线程
文章目录 0 前言1. 为什么Redis是单线程?1.1 Redis单线程1.2 为什么Redis3时代单线程快的原因1.3 使用单线程原因 2.为什么逐渐加入多线程呢?2.1 如何解决 3.redis6/7的多线程特性和IO多路复用入门3.1主线程和IO线程怎么协作完成请求处理的3.2 Unix网络编…...

【C++】STL——priority_queue优先级队列
目录 前言priority_queue的使用简单使用在OJ中的使用 priority_queue的模拟实现基本功能仿函数在这里插入图片描述 前言 上一节我们说了stack和queue这两种容器适配器,而priority_queue(优先级队列)同样也是属于容器适配器,它会优…...

大数据新视界 --大数据大厂之大数据在智慧城市建设中的应用:打造智能生活的基石
💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

使用枚举来实现策略模式
使用很多if else的场景 public void save(String type,Object data){if("db".equals(type)){saveInDb(data);}else if("file".equals(type)){saveInFile(data);}else if("oss".equals(type)){saveInOss(data);}}使用枚举来解决 public enum Save…...

区块链技术原理
1. 引言 区块链的定义 区块链是一种分布式账本技术(Distributed Ledger Technology,DLT),其核心特征是通过密码学的方式将数据打包成一个个区块,按时间顺序依次相连,形成一个不可篡改、公开透明的链式数据…...

Spring Boot 接口数据加解密
今天聊下接口安全问题,涉及到接口的加密和解密 经常和外部单位接口调用梳理了相关技术方案,主要的需求点如下: 1,尽量少改动,不影响之前的业务逻辑 2,考虑到时间紧迫性,可采用对称性加密方式&…...

2018年计算机网络408真题解析
第一题: 解析:TCP/IP体系结构应用层常用协议及其相应的运输层协议 TCP协议是面向连接可靠数据传输服务,UDP无连接不可靠的数据传输服务,IP无连接不可靠的数据连接服务。 FTP协议,SMTP协议和HTTP协议使用TCP协议提供的面…...

Javascript 脚本查找B站限时免费番剧
目录 前言 脚本编写 脚本 前言 B站的一些番剧时不时会“限时免费”,白嫖党最爱,主打一个又占到便宜的快乐。但是在番剧索引里却没有搜索选项可以直接检索“限时免费”的番剧,只能自己一页一页的翻去查看,非常麻烦。 自己找限…...

YoloV10改进策略:主干网络改进|DeBiFormer,可变形双级路由注意力|全网首发
摘要 在目标检测领域,YoloV10以其高效和准确的性能而闻名。然而,为了进一步提升其检测能力,我们引入了DeBiFormer作为YoloV10的主干网络。这个主干网络的计算量比较大,不过,上篇双级路由注意力的论文受到很大的关注,所以我也将这篇论文中的主干网络用来改进YoloV10,卡多…...

C#学习笔记(一)
C#学习笔记(一) 简介第一章 上位机开发环境之 VS 使用和.NET 平台基础一、安装软件二、创建项目三、第一个Hello world四、解决方案与项目五、Debug 和 Release 的区别六、代码的生产过程七、CLR的其它功能 简介 C# .NET工控上位机开发 在工控领域&…...

MATLAB边缘检测
一、目的: 熟悉边缘检测原理,并运用matlab软件实现图像的canny边缘检测,体会canny边缘检测的优缺点。 二、内容: 编写matlab程序,实现对lena图像的边缘检测,输出程序运行结果。 三、原理或步骤&#x…...

Tortoise SVN 安装汉化教程(乌龟SVN)
1.首先下载 去官网下载 如果下载比较慢的,链接自取 https://pan.quark.cn/s/cb6f2eee3f90 2. 安装Tortoise SVN 无脑next到完成 最后到桌面右键 你就发现svn出来了,但是是英文的!!!! 像我这种英文不好的…...

深入了解Spring重试组件spring-retry
在我们的项目中,为了提高程序的健壮性,很多时候都需要有重试机制进行兜底,最多就场景就比如调用远程的服务,调用中间件服务等,因为网络是不稳定的,所以在进行远程调用的时候偶尔会产生超时的异常࿰…...

海南聚广众达电子商务咨询有限公司靠谱吗怎么样?
在当今这个数字化浪潮席卷全球的时代,抖音电商以其独特的魅力成为了众多商家争相入驻的新蓝海。而在这片浩瀚的电商海洋中,如何找到一家既专业又可靠的合作伙伴,成为了众多商家心中的一大难题。今天,我们就来深入剖析一下海南聚广…...

Java的魔法世界:面向对象编程(OOP)是什么?
这个嘎嘎重要 面向对象编程(OOP)是让Java像玩具世界一样,把现实中的东西变成“对象”,然后让这些对象去互动。你可以想象OOP是Java的“魔法世界”,通过创建“对象”(Object),让它们有…...