SpringCache 缓存 - @Cacheable、@CacheEvict、@CachePut、@Caching、CacheConfig 以及优劣分析
目录
SpringCache 缓存
环境配置
1)依赖如下
2)配置文件
3)设置缓存的 value 序列化为 JSON 格式
4)@EnableCaching
实战开发
@Cacheable
@CacheEvict
@CachePut
@Caching
@CacheConfig
SpringCache 的优势和劣势
读操作(优势)
写操作(劣势)
总结
SpringCache 缓存
环境配置
1)依赖如下
父依赖 SpringBoot 3.2.5
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
2)配置文件
spring:cache:type: redisredis:time-to-live: 3600000# key-prefix: CACHE_use-key-prefix: true cache-null-values: true
- time-to-live: 3600000 -> 缓存过期时间,单位毫秒,此处相当于 1 小时(实际上也就解决了雪崩问题,因为一般设置每一个缓存时的时间线不一样)
- key-prefix: CACHE_ -> 缓存 key 前缀(一般不用这个属性,而是使用分区名作为 key 前缀)
- use-key-prefix: true -> 是否使用缓存分区名作为 key 前缀(分区名在 @Cacheable 中指定),建议为 true
- cache-null-values: true -> 是否缓存空值(解决缓存穿透问题),建议为 true
3)设置缓存的 value 序列化为 JSON 格式
import org.springframework.boot.autoconfigure.cache.CacheProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cache.annotation.EnableCaching
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
import org.springframework.data.redis.serializer.RedisSerializationContext
import org.springframework.data.redis.serializer.StringRedisSerializer@Configuration
@EnableConfigurationProperties(CacheProperties::class) //让配置文件中的配置生效
@EnableCaching // 开启 SpringCache 缓存功能(如果这里不写这个注解,启动类上也一定要有!!!)
class MyCacheConfig {@Beanfun redisCacheConfiguration(cacheProperties: CacheProperties): RedisCacheConfiguration {//这里源码怎么写,咱们咱们写(只需要改一下缓存 value 的序列化方式即可)var config = RedisCacheConfiguration.defaultCacheConfig()//设置 key value 的序列化方式config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(StringRedisSerializer()))config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(GenericJackson2JsonRedisSerializer()))val redisProperties = cacheProperties.redis//将配置文件中的所有配置都生效redisProperties.timeToLive?.let {config = config.entryTtl(it)}redisProperties.keyPrefix?.let {config = config.prefixCacheNameWith(it)}if (!redisProperties.isCacheNullValues) {config = config.disableCachingNullValues()}if (!redisProperties.isUseKeyPrefix) {config = config.disableKeyPrefix()}return config}}
4)@EnableCaching
@EnableCaching 表示开启 SpringCache 缓存功能,加在 启动类 或者 配置类 上都可以.
实战开发
@Cacheable
a)使用说明:
@Cacheable 用来将方法的返回值数据保存到缓存中.
常用属性如下:
- value:表示将当前缓存数据放到哪个 缓存组 中(可以理解为放到哪个文件夹下).
- 例如 @Cacheable(value = ["user"])
- key:指定 key 是什么. 接受一个 SpEL 表达式,例如如下表格中的示例
- 例如方法名作为 key:@Cacheable(value = ["user"], key = "#root.method.name")
- 另外,如果不想使用 SpEL 表达式,可以直接在双引号内加上一对单引号,例如 key 为 "userinfo":@Cacheable(value = ["user"], key = "'userinfo'")
- condition:条件判断属性,只有符合条件才可以被缓存.
- 例如方法参数中的 id > 0 返回值才能被缓存 @Cacheable(value = ["user"], key = "#root.method.name", condition = "#id > 0")
- sync:是否为同步执行. 如果设置为 true,会加锁(本地锁),可以用来解决击穿问题.
b)案例如下:
例如通过 SpEL表达式设置 缓存的 key 为 动态的id + "userinfo" ,
@Cacheable(value = ["user"], key = "#id + 'userinfo'")override fun getUserinfo(id: Long): UserinfoVo {//业务逻辑...println("查询数据库...")return UserinfoVo( // 这里的 UserinfoVo 必须要有无参构造才行,否则缓存将来读取的时候会报错id = id,name = "cyk",age = 21,)}
第一查询之后,就可以看到 Redis 上面已经存在该数据. 之后的只要缓存未过期,都会直接查缓存.
@CacheEvict
a)使用说明
@CacheEvict 用来将数据从缓存中删除.
他常常被用来实现 “失效模式” 来解决缓存一致性问题(数据库中的数据被更新之后,直接删除缓存上的数据即可,下次查询的时候,自动同步到缓存上).
常用属性和 @Cacheable 差不多,这里不再赘述.
b)案例如下
例如实现缓存失效:现在要进行用户信息的修改,那么为了保证缓存和数据库中数据一致,修改完数据库之后的就直接删除对应的缓存数据即可~ 下次查询时,再更新缓存.
这里通过 SpEL 表达式设置要删除的缓存的 key 为 动态的id + "userinfo" ,
/*** 通过 @CacheEvict 实现缓存失效,下次查询时,再更新缓存*/@CacheEvict(value = ["user"], key = "#dto.id + 'userinfo'")override fun updateUserinfo(dto: UserinfoDto) {//业务逻辑...println("修改数据库数据...")}
另外,还可以通过 属性,删除同一个分区下的所有缓存(慎用)
@CacheEvict(value = ["user"], allEntries = true)
@CachePut
a)使用说明
@CachePut 用来更新缓存数据.
与 @Cacheable 不同的是,使用 @CachePut 标注的方法在执行前不会检查缓存中是否存在这个数据,而是每次都会执行这个方法,并将返回值写入到缓存中.
属性上和 @Cacheable 是一样的,这里不再赘述.
b)案例如下
@CachePut(value = ["user"], key = "#dto.id + 'userinfo'")override fun putUserinfo(dto: UserinfoDto): UserinfoVo {//业务逻辑println("更新数据库...")return with(dto) {UserinfoVo(id = id,name = name,age = age,)}}
@Caching
@Caching 用来组合以上多个操作.
例如删除同时删除多个缓存数据
@Caching(evict = [CacheEvict(value = ["user"], key = "#dto.id + 'userinfo'"),CacheEvict(value = ["user"], key = "#dto.id + 1 + 'userinfo'"),])override fun updateUserinfo(dto: UserinfoDto) {//业务逻辑...println("修改数据库数据...")}
@CacheConfig
如果一个类中有很多一样的 cacheName、keyGenerator、cacheManager、cacheResolver,可以直接使用 @CacheConfig 在类上声明,那么这个类中的所有标记了 Cache 相关注解的方法都会共享 @CacheConfig 属性
@Service
//@CacheConfig(cacheNames = ["aaa", "bbb"]) 会创建两个缓存分区, aaa 和 bbb
@CacheConfig(cacheNames = ["user"])
class CacheServiceImpl: CacheService {@Cacheable(key = "#id + 'userinfo'")override fun getUserinfo(id: Long): UserinfoVo {//业务逻辑...println("查询数据库...")return UserinfoVo( // 这里的 UserinfoVo 必须要有无参构造才行,否则缓存将来读取的时候会报错id = id,name = "cyk",age = 21,)}/*** 通过 @CacheEvict 实现缓存失效,下次查询时,再更新缓存*/@CacheEvict(key = "#dto.id + 'userinfo'")override fun updateUserinfo(dto: UserinfoDto) {//业务逻辑...println("修改数据库数据...")}@CachePut(key = "#dto.id + 'userinfo'")override fun putUserinfo(dto: UserinfoDto): UserinfoVo {//业务逻辑println("更新数据库...")return with(dto) {UserinfoVo(id = id,name = name,age = age,)}}}
SpringCache 的优势和劣势
读操作(优势)
SpringCache 在读操作上的处理的还是很到位的:
- 缓存穿透:配置文件中设置 cache-null-values: true,这样就会将查询为 null 也缓存起来.
- 缓存击穿:配置文件中设置 sync=true,这样就可以对方法进行加锁,解决击穿问题.
- 缓存雪崩:配置文件中设置 time-to-live=3600000 用来设置过期时间(虽然设置的时间是统一的,但是一般情况下情况下触发的时机是不同的,也就相当于是有了随机因子).
写操作(劣势)
- 对于读写并发高,或者写并发高的场景不太好应对.
- 针对于一些特殊的写场景,还是要定制化一下的
总结
对于读多写少,一致性要求不高的数据,完全可以使用 SpringCache 来简化开发(只要缓存的数据有过期时间就可以).
对于一致性要求高的场景,也没必要引入引入缓存,直接对数据库进行读写即可.
特殊数据特殊处理.
相关文章:

SpringCache 缓存 - @Cacheable、@CacheEvict、@CachePut、@Caching、CacheConfig 以及优劣分析
目录 SpringCache 缓存 环境配置 1)依赖如下 2)配置文件 3)设置缓存的 value 序列化为 JSON 格式 4)EnableCaching 实战开发 Cacheable CacheEvict CachePut Caching CacheConfig SpringCache 的优势和劣势 读操作…...

数据结构 —— 堆
1.堆的概念及结构 堆是一种特殊的树形数据结构,称为“二叉堆”(binary heap) 看它的名字也可以看出堆与二叉树有关系:其实堆就是一种特殊的二叉树 堆的性质: 堆中某个结点的值总是不大于或不小于其父结点的值&…...
【运维】如何更换Ubuntu默认的Python版本,update-alternatives如何使用
update-alternatives 是一个在 Debian 及其衍生发行版中(包括 Ubuntu)用于管理系统中可替代项的命令。它可以用于在系统中设置默认的软件版本,例如在不同版本的软件之间进行切换,比如不同的 Python 版本。 要在 Ubuntu 中使用 up…...

2024 年适用于 Linux 的 5 个微软 Word 替代品
对于那些最近由于隐私问题或其他原因而转向 Linux 的用户来说,可能很难替换他们最喜欢的、不在 Linux 操作系统上运行的应用程序。 寻找流行程序的合适替代品可能会成为一项挑战,而且并不是每个人都准备好花费大量时间来尝试弄清楚什么可以与他们在 Win…...
大模型日报2024-06-12
大模型日报 2024-06-12 大模型资讯 NVIDIA发布GB200 Grace Blackwell AI超级芯片 摘要: NVIDIA近日宣布推出GB200 Grace Blackwell超级芯片和Blackwell B200 GPU,这些新技术将推动人工智能领域的发展。 阿布扎比TII发布下一代Falcon语言模型 摘要: 阿布扎比的技术创…...

LVGL欢乐桌球游戏(LVGL+2D物理引擎学习案例)
LVGL欢乐桌球游戏(LVGL2D物理引擎学习案例) 视频效果: https://www.bilibili.com/video/BV1if421X7DL...

国产数字证书大品牌——JoySSL
一、品牌介绍 网盾安全旗下品牌JoySSL是专业的https安全方案服务商,业务涉及网络安全技术服务、安全防护系统集成、数据安全软件开发等。网盾安全以网络安全为己任,携手GlobalSign、DigiCert 、Sectigo等全球数家权威知名SSL证书厂商,加速ht…...

Codeforces Global Round 26 D. “a“ String Problem 【Z函数】
D. “a” String Problem 题意 给定一个字符串 s s s,要求把 s s s 拆分成若干段,满足以下要求: 拆分出来的每一个子段,要么是子串 t t t,要么是字符 a a a子串 t t t 至少出现一次 t ≠ " a " t \ne…...
Next.js 加载页面及流式渲染(Streaming)
Next.js 加载页面及流式渲染(Streaming) 在现代的 Web 应用开发中,用户体验是至关重要的。快速响应的页面加载和流畅的用户界面可以显著提升用户的满意度。而加载页面(Loading Page)和流式渲染(Streaming&…...

形如SyntaxError: EOL while scanning string literal,以红色波浪线形式在Pycharm下出现
背景: 新手在学习Python时可能会出现如下图所示的报错 下面分情况教大家如何解决 视频教程【推荐】: 形如SyntaxError: EOL while scanning string literal,以红色波浪线形式在Pycharm下出现 过程: 问题概述: 简单…...

DockerCompose+Jenkins+Pipeline流水线打包SpringBoot项目(解压安装配置JDK、Maven等)入门
场景 DockerCompose中部署Jenkins(Docker Desktop在windows上数据卷映射): DockerCompose中部署Jenkins(Docker Desktop在windows上数据卷映射)-CSDN博客 DockerJenkinsGiteeMaven项目配置jdk、maven、gitee等拉取代…...
Web前端开发个人技能全面剖析:四维度深度理解,五能力实战展现,六要素构建优势,七步骤持续精进
Web前端开发个人技能全面剖析:四维度深度理解,五能力实战展现,六要素构建优势,七步骤持续精进 在数字化浪潮的推动下,Web前端开发成为了互联网行业中的热门岗位,对个人的技能要求也越来越高。本文将从四个…...
如何让 uboot启动时自动执行指令?(执行“mtdparts default”命令)
让uboot启动时自动设置分区(执行“mtdparts default”命令),在uboot进入main_loop()死循环之前添加执行命令代码 run_command("mtdparts default", 0); #define MTDIDS_DEFAULT "nand0mini2440-nand" #define MTD…...

Java的集合框架总结
Map接口和Collection接口是所有集合框架的父接口: Collection接口的子接口包括:Set接口和List接口 Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等 Set接口的实现类主要有:HashSet、Tr…...

基于DenseNet网络实现Cifar-10数据集分类
目录 1.作者介绍2.Cifar-10数据集介绍3.Densenet网络模型3.1网络背景3.2网络结构3.2.1Dense Block3.2.2Bottleneck层3.2.3Transition层3.2.4压缩 4.代码实现4.1数据加载4.2建立 DenseNet 网络模型4.3模型训练4.4训练代码4.5测试代码 参考链接 1.作者介绍 吴思雨,女…...
我的“工具”库
#使用到的工具# { 网页版的VScode: www.vscode.dev} {网页版JSON文件编辑器: JSON Editor Online: edit JSON, format JSON, query JSON } {网页版XML文件编辑器: Best Online XML Viewer, XML Formatter, XML Editor, Analyser, Be…...
Pytorch常用函数用法归纳:Tensor张量之间的计算
1.torch.add() (1)函数原型: torch.add(input, other, alpha, out) (2)参数说明: 参数名称参数类型参数说明inputtorch.Tensor表示参与运算的第一个输入Tensor张量othertorch.Tensor或者Number表示参与运算的第二个输入Tensor张量或标量alphaNumber, optional一个可选的缩放…...

小公司要求真高
大家好,我是白露啊。 最近看到一个爽文帖,标题就是——“小公司要求真高”。 事情是这样的,一家的小公司在拿到简历之后,HR直接对楼主说:“你不合适,简历不行。” 言外之意就是嫌弃简历单薄,看…...

进阶篇02——索引
概述 结构 B树索引 在这里推荐一个可以将个各种数据结构可视化的网站:数据结构可视化 哈希索引 相关的一个面试题 分类 聚集索引和二级索引(非聚集索引) 思考题:索引思考题 创建索引语法 如果一个索引关联多个字段ÿ…...

三:SpringBoot的helloworld和使用Springboot的优点以及快速创建Springboot应用
三:SpringBoot的helloworld和使用Springboot的优点以及快速创建Springboot应用 一:HelloWorld [我们创建的是maven项目或者直接创建一个Spring] 1.1:创建一个maven 项目(1】:需要自己手动写一个SpringBoot 的启动类同…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
Python网页自动化Selenium中文文档
1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API,让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API,你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...