Spring Boot 缓存注解详解:@Cacheable、@CachePut、@CacheEvict(超详细实战版)
💡 前言
在高并发、高性能的系统开发中,缓存是提升接口响应速度和降低数据库压力的重要手段。Spring Boot 提供了强大的缓存抽象层 —— spring-context-support
,并结合 JSR-107 标准,提供了多个缓存注解,如:
@Cacheable
@CachePut
@CacheEvict
这些注解可以让我们在不侵入业务逻辑的前提下,轻松实现方法级别的缓存管理。
本文将带你从零开始掌握 Spring Boot 中常用的缓存注解,并通过多个实际案例演示其强大功能,包括:
- 查询缓存优化
- 数据更新同步
- 删除缓存策略
- 多级缓存架构设计
- Redis 实战整合
- 缓存穿透、击穿、雪崩的解决方案
无论你是初学者,还是有一定经验的开发者,这篇文章都能让你快速上手 Spring Boot 缓存机制!
📦 一、Spring Boot 缓存核心机制概述
✅ 缓存抽象原理
Spring 的缓存机制基于 AOP 实现,本质上是在方法执行前后插入缓存逻辑:
注解 | 功能 |
---|---|
@Cacheable | 先查缓存,有则返回;没有则执行方法并将结果缓存 |
@CachePut | 执行方法后更新缓存(常用于新增或更新操作) |
@CacheEvict | 清除缓存(常用于删除或刷新缓存) |
📌 注意:
- 这些注解只能用在
public
方法上; - 只有当调用方通过 Spring 代理调用该方法时才生效(即不能在同一个类中直接调用带注解的方法);
- 需要启用缓存功能:
@EnableCaching
🛠️ 二、快速入门:开启缓存支持
Step 1:添加依赖(以 Redis 为例)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
也可以使用本地缓存如 Caffeine
或 Ehcache
。
Step 2:启用缓存
@SpringBootApplication
@EnableCaching
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
🔁 三、三大缓存注解详解与实战
✅ 1. @Cacheable:查询缓存,避免重复计算
场景说明:
当你有一个查询接口,数据变更频率低,但查询频繁,就可以使用 @Cacheable
来缓存结果。
示例代码:
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Cacheable(value = "users", key = "#userId")public User getUserById(Long userId) {System.out.println("【真实查询】用户ID:" + userId);return userRepository.findById(userId).orElse(null);}
}
参数说明:
value
/cacheNames
:指定缓存名称,可理解为缓存区域;key
:缓存键,默认使用参数生成;unless
:条件判断,例如unless = "#result == null"
表示结果为空时不缓存;condition
:根据条件决定是否缓存,例如condition = "#userId > 0"
。
✅ 2. @CachePut:更新缓存,保持一致性
场景说明:
当你对数据进行了更新或新增操作,需要同步更新缓存,保证下次查询拿到的是最新数据。
示例代码:
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {return userRepository.save(user);
}
📌 注意:
@CachePut
总是会执行方法体,并将结果放入缓存;- 常用于新增、修改等写操作。
✅ 3. @CacheEvict:清除缓存,强制刷新
场景说明:
当你删除某个数据或批量清空缓存时,就需要使用 @CacheEvict
。
示例代码:
@CacheEvict(value = "users", key = "#userId")
public void deleteUser(Long userId) {userRepository.deleteById(userId);
}
清空整个缓存区:
@CacheEvict(value = "users", allEntries = true)
public void clearAllUsers() {// 删除所有用户逻辑
}
📌 参数说明:
allEntries = true
:清空该缓存区域下的所有键;beforeInvocation = true
:是否在方法执行前清空缓存(默认 false,在方法执行后)。
🎯 四、进阶技巧与最佳实践
✅ 1. 自定义缓存 Key 生成策略
可以通过实现 KeyGenerator
接口自定义缓存 key 的生成方式:
@Bean
public KeyGenerator customKeyGenerator() {return (target, method, params) -> {StringBuilder sb = new StringBuilder();sb.append(target.getClass().getSimpleName());sb.append(method.getName());for (Object obj : params) {sb.append(obj.toString());}return sb.toString();};
}
然后在注解中使用:
@Cacheable(value = "users", keyGenerator = "customKeyGenerator")
✅ 2. 设置缓存过期时间(以 Redis 为例)
在 application.yml
中配置:
spring:redis:timeout: 60scache:redis:time-to-live: 3600000 # 1小时
✅ 3. 多级缓存策略(Redis + Caffeine)
为了进一步提升性能,可以采用“本地缓存 + 分布式缓存”的组合方案:
- 使用
Caffeine
作为本地缓存,减少网络开销; - 使用
Redis
作为分布式缓存,确保多节点间数据一致。
示例配置:
@Configuration
public class CacheConfig {@Beanpublic CacheManager caffeineCacheManager() {CaffeineCacheManager cacheManager = new CaffeineCacheManager("localUsers");cacheManager.setCacheBuilder(Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES));return cacheManager;}@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new GenericJackson2JsonRedisSerializer());template.afterPropertiesSet();return template;}
}
✅ 4. 缓存穿透、击穿、雪崩解决方案
问题 | 解决方案 |
---|---|
缓存穿透 | 缓存空值、使用布隆过滤器 |
缓存击穿 | 加互斥锁、设置永不过期 |
缓存雪崩 | 设置不同过期时间、集群缓存 |
示例:防止缓存穿透
@Cacheable(value = "products", key = "#productId", unless = "#result == null")
public Product getProductById(Long productId) {Product product = productRepository.findById(productId).orElse(null);if (product == null) {// 缓存空值,防止缓存穿透redisService.setWithExpire("product:" + productId, "", 60, TimeUnit.SECONDS);}return product;
}
🧩 五、综合案例:商品信息缓存实战
背景:
我们有一个商品服务,包含如下功能:
- 查询商品详情(缓存)
- 更新商品信息(更新缓存)
- 删除商品(清除缓存)
代码示例:
@Service
public class ProductService {@Autowiredprivate ProductRepository productRepository;@Cacheable(value = "products", key = "#productId")public Product getProductById(Long productId) {return productRepository.findById(productId).orElse(null);}@CachePut(value = "products", key = "#product.id")public Product updateProduct(Product product) {return productRepository.save(product);}@CacheEvict(value = "products", key = "#productId")public void deleteProduct(Long productId) {productRepository.deleteById(productId);}
}
📘 六、常见问题与解决方案
问题 | 原因 | 解决办法 |
---|---|---|
注解不生效 | 没加 @EnableCaching | 添加注解 |
同一类内调用失效 | AOP 代理失效 | 将方法抽离到另一个 Bean 中 |
缓存未更新 | 没使用 @CachePut 或 @CacheEvict | 加上对应注解 |
key 冲突 | key 重复导致覆盖 | 使用更细粒度的 key 策略 |
不支持序列化 | 缓存对象未实现 Serializable | 使用 JSON 序列化或实现接口 |
🧭 七、总结对比表
注解 | 作用 | 是否执行方法 | 适用场景 |
---|---|---|---|
@Cacheable | 查询缓存 | 有缓存则跳过方法 | 查询频繁、更新少的数据 |
@CachePut | 更新缓存 | 总是执行方法 | 新增/修改操作 |
@CacheEvict | 删除缓存 | 总是执行方法 | 删除或刷新缓存 |
🎁 八、结语
Spring Boot 的缓存注解为我们提供了一种声明式的缓存管理方式,极大地提升了开发效率和系统性能。无论是构建企业级后台系统,还是搭建高并发 API 平台,都应该合理使用缓存来优化系统表现。
通过本文的学习,你已经掌握了:
- 如何使用
@Cacheable
、@CachePut
、@CacheEvict
; - 如何结合 Redis 或本地缓存进行实际应用;
- 如何避免缓存穿透、雪崩、击穿等问题;
- 如何提高系统的响应速度和稳定性。
🎯 点赞、收藏、转发本文,让更多开发者受益!
相关文章:
Spring Boot 缓存注解详解:@Cacheable、@CachePut、@CacheEvict(超详细实战版)
💡 前言 在高并发、高性能的系统开发中,缓存是提升接口响应速度和降低数据库压力的重要手段。Spring Boot 提供了强大的缓存抽象层 —— spring-context-support,并结合 JSR-107 标准,提供了多个缓存注解,如ÿ…...

【设计模式-4.8】行为型——中介者模式
说明:本文介绍行为型设计模式之一的中介者模式 定义 中介者模式(Mediator Pattern)又叫作调节者模式或调停者模式。用一个中介对象封装一系列对象交互,中介者使各对象不需要显式地互相作用,从而使其耦合松散…...
SpringCloud-基于SpringAMQP实现消息队列
在微服务架构中,使用消息队列进行异步通信是一种常见而有效的方法。Spring Cloud提供了一个强大的工具集,用于构建分布式系统,而Spring AMQP是其支持高级消息队列协议(AMQP)的组件,广泛应用于消息队列的场景中,尤其是与…...
ObjectMapper 在 Spring 统一响应处理中的作用详解
ObjectMapper 是 Jackson 库的核心类,专门用于处理 JSON 数据的序列化(Java 对象 → JSON)和反序列化(JSON → Java 对象)。在你提供的代码中,它解决了字符串响应特殊处理的关键问题。 一、为什么需要 Obj…...
H5移动端性能优化策略(渲染优化+弱网优化+WebView优化)
一、渲染优化:首屏速度提升的核心 1. 关键页面采用SSR或Native渲染 适用场景:首页、列表页、详情页等强内容展示页面 优化原理: SSR(服务端渲染):在服务端生成完整…...
【汇编逆向系列】二、函数调用包含单个参数之整型-ECX寄存器,LEA指令
目录 一. 汇编源码 二. 汇编分析 1. ECX寄存器 2. 栈位置计算 3. 特殊指令深度解析 三、 汇编转化 一. 汇编源码 single_int_param:0000000000000040: 89 4C 24 08 mov dword ptr [rsp8],ecx0000000000000044: 57 push rdi0000…...

行列式的性质
1 行列式使用如下性质定义 1)单位矩阵行列式值为 1, ,对于任意单位矩阵均成立; 2)当矩阵交换一行后,行列式值改变符号,如置换矩阵的行列式值为 (根据行交换次数决定)&…...

联软NSPM自动化策略管理 助力上交所加速国产化替代提升运维效率
在金融行业核心基础设施国产化浪潮与网络安全强监管的双重背景下,上海证券交易所(以下简称“上交所”)积极拥抱变革,携手长期合作伙伴联软科技,成功部署了联软安全策略管理系统(NSPM)。该项目不…...

Flask + ECharts+MYSQL物联网数字化大屏
基于Flask+ECharts的物联网数字化大屏系统,包含中国地图实时数据更新功能。这个系统模拟了物联网设备在全国范围内的分布和运行状况,并实时更新数据。 一、系统架构设计 技术栈 后端:Flask(轻量级路由+API支持) 前端:ECharts(地图+动态图表)、WebSocket(实时更新)…...
业务到解决方案构想
解决方案构想的核心理解 解决方案构想是连接业务需求与技术实现的关键桥梁,从您描述的内容和我的理解,这个阶段的核心点包括: 核心要点解读 转化视角:将业务视角的需求转变为解决方案视角 业务能力探索阶段识别了"做什么&q…...

数据库系统概论(十六)数据库安全性(安全标准,控制,视图机制,审计与数据加密)
数据库系统概论(十六)数据库安全性 前言一、数据库安全性1. 什么是数据库安全性?2. 为何会存在安全问题? 二、安全标准的发展1. 早期的“开拓者”:TCSEC标准2. 走向国际统一:CC标准3. TCSEC和CC标准有什么不…...

vue3从入门到精通(基础+进阶+案例)
Vue是什么? 渐进式JavaScript框架,易学易用,性能出色,适用场景丰富的Web前端框架 为什么要学习Vue Vue是目前前端最火的框架之一 Vue是目前企业技术栈中要求的知识点 Vue可以提升开发体验 。。。 Vue简介 Vue(发音为/vju/,…...

【Linux 学习计划】-- 系统中进程是如何调度的(内核进程调度队列)
目录 回顾进程优先级与进程调度的引入 内核runqueue图例 关于queue[140]前100个位置 | 实时进程与分时进程 遍历需要调度的进程与bitmap的引入 active、expired指针 结语 回顾进程优先级与进程调度的引入 在我们之前的学习中,我们是有学习过进程优先级这个概…...
gemini和chatgpt数据对比:谁在卷性能、价格和场景?
先把结论“剧透”给赶时间的朋友:顶配 Gemini Ultra/2.5 Pro 在纸面成绩上普遍领先,而 ChatGPT 家族(GPT-4o / o3 / 4.1)则在延迟、生态和稳定性上占优。下面把核心数据拆开讲,方便你对号入座。附带参考来源࿰…...

C#、VB.net——如何设置窗体应用程序的外边框不可拉伸
以Visual studio 2015为例,具体操作如下: 1、将窗体的“FormBorderStyle”属性值修改为“FixedSingle”: 2、点击“格式”——“锁定控件”: 这样生成的程序边框即可固定住,无法拉伸。...

基于SpringBoot的房屋租赁系统的设计与实现(thymeleaf+MySQL)
💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...

Spring Boot统一功能处理深度解析
第一章:为什么需要统一功能处理? 想象你正在开发一个电商系统,包含用户管理、商品管理、订单管理等模块。每个模块都需要: 用户身份验证操作日志记录异常统一处理数据格式标准化 如果每个模块都单独实现这些功能: …...

世事无常,比较复杂,人可以简单一点
2025年6月5日日,17~28℃,一般 待办: 宣讲会 职称材料的最后检查 职称材料有错误,需要修改 期末考试试题启用 教学技能大赛PPT 遇见:部门宣传泰国博士项目、硕士项目、本科项目。 感受或反思:东南亚博士…...
使用 Docker Compose 安装 PostgreSQL 16
前面是指南,后面是实际工作日志。 1. 创建 docker-compose.yml 文件 yaml 复制 下载 version: 3.9 services:postgres:image: postgres:16container_name: postgres-16environment:POSTGRES_USER: your_username # 替换为你的用户名POSTGRES_PASSWORD: your…...
每日算法刷题Day23 6.5:leetcode二分答案3道题,用时1h40min(有点慢)
8. 3007.价值和小于等于K的最大数字(中等,学习,太难,先过) 3007. 价值和小于等于 K 的最大数字 - 力扣(LeetCode) 思想 1.给你一个整数 k 和一个整数 x 。整数 num 的价值是它的二进制表示中在 x,2x,3x …...
【Android基础回顾】七:内存管理机制
Android 的内存管理机制是一个多层次的复杂系统,旨在高效利用有限的物理内存(RAM),在保证前台应用流畅运行的同时,尽可能在后台保留更多应用以提高启动速度(多任务)。 它的核心机制结合了 Linu…...

数据结构哈希表总结
349. 两个数组的交集 力扣题目链接(opens new window) 题意:给定两个数组,编写一个函数来计算它们的交集。 说明: 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。 public int[] intersection(int[] nums1, int[] num…...
Spring事务失效-----十大常见场景及解决方案全解析
Spring事务失效的常见场景及原因分析 Spring事务管理是开发中的核心功能,但在实际应用中可能因各种原因导致事务失效。以下是常见的事务失效场景及详细解析: 1. 方法未被Spring管理 场景:使用new关键字直接创建对象,而非通过Spring容器注入原因:Spring事务基于AOP代理,…...
KMP 算法中 next 数组的构建函数 get_next
KMP 算法中 next 数组的构建函数 get_next ,负责计算模式串的 next 数组,核心是通过递推找到每个位置的 “最长相等前缀后缀长度”。(下标从 1 开始): 一、函数作用 get_next(SString T, int next[]) 的任务…...

IDEA 开发PHP配置调试插件XDebug
1、安装PHP环境 为了方便,使用的PhpStudy。 安装路径:D:\resources\phpstudy_pro\Extensions\php\php7.3.4nts 2、下载Xdebug Xdebug: Downloads 选择对应的版本下载,本次使用的是7.3。 3、配置Xdebug 在php.ini中添加Xdebug配置。 D…...

奇异值分解(SVD):线性代数在AI大模型中的核心工具
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...
矩阵分解相关知识点总结(二)
文章目录 三、矩阵的QR分解3.1、Givens矩阵与Givens变换3.2、Householder矩阵与Householder变换3.3、QR分解 书接上文矩阵分解相关知识点总结(一) 三、矩阵的QR分解 3.1、Givens矩阵与Givens变换 设非零列向量 x ∈ R n \bm{x}\in {\bf{R}}^n x∈Rn及单…...

MySQL——视图 用户管理 语言访问
目录 视图 用户管理 数据库权限 访问 准备工作 使用函数 mysql界面级工具 连接池 视图 这里的视图与事务中的读视图是两个不同的概念:视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。视图的…...

二、Sqoop 详细安装部署教程
作者:IvanCodes 日期:2025年6月2日 专栏:Sqoop教程 Apache Sqoop 是一个强大的工具,用于在 Hadoop (HDFS, Hive, HBase) 与关系型数据库 (如 MySQL, PostgreSQL, Oracle) 之间高效传输数据。本教程将详细指导您如何根据官方网站截…...
用Python开启游戏开发之旅
在当今丰富多彩的数字娱乐世界中,游戏以其独特的魅力吸引着无数人的目光。而Python这门功能强大又简洁易懂的编程语言,也为游戏开发打开了一扇充满创意的大门。 一、选择Python的理由 Python之所以备受游戏开发者青睐,有诸多原因。其一&#…...