重学SpringBoot3-集成Redis(二)之注解驱动
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍
重学SpringBoot3-集成Redis(二)之注解驱动
- 1. 为什么选择 Redis 作为缓存?
- 2. 如何在 Spring Boot 中启用 Redis 缓存?
- 2.1 添加 Redis 依赖
- 2.2 配置 Redis 连接
- 2.3 启用缓存支持
- 3. 注解驱动的缓存机制
- 3.1 @Cacheable示例
- 3.2 @CachePut示例
- 3.3 @CacheEvict示例
- 4. 自定义缓存管理
- 4.1 RedisCacheConfiguration 类
- 4.1.1. 过期时间(TTL - Time To Live)
- 4.1.2. 键序列化方式
- 4.1.3. 值序列化方式
- 4.1.4. 禁用缓存空值(Disable Caching Null Values)
- 4.1.5. 使用前缀(Use Cache Key Prefixes)
- 4.1.6. 设置空闲时间(Idle Time)
- 4.1.7. 组合多种配置
- 4.1.8. 设置自定义的过期策略
- 4.2 自定义缓存配置
- 5. Redis 缓存的常见问题和优化建议
- 6. 总结
Spring Boot 提供了对缓存的简便支持,使得开发者能够通过简单的注解实现缓存操作,减少重复代码的编写。本文将详细介绍如何在 Spring Boot 3 中使用 Redis 作为缓存,并通过注解驱动的方式进行缓存操作。
1. 为什么选择 Redis 作为缓存?
Redis 是一个高效的键值对存储系统,特别适合于构建高性能、可扩展的缓存层。其优点包括:
- 高吞吐量:Redis 使用内存作为存储介质,读取和写入性能极快,能够支撑高并发的访问需求。
- 数据持久化:尽管 Redis 是内存数据库,它也支持将数据持久化到磁盘,防止数据丢失。
- 丰富的数据结构:Redis 不仅支持简单的字符串存储,还支持哈希、列表、集合等丰富的数据结构,适用于多种应用场景。
- 易于扩展:通过 Redis 的集群功能,可以很容易地扩展 Redis 实例,处理更大规模的数据和请求。
2. 如何在 Spring Boot 中启用 Redis 缓存?
Spring Boot 提供了对缓存的开箱即用支持,开发者只需简单配置即可使用。具体参考上一章 重学SpringBoot3-集成Redis(一)。
2.1 添加 Redis 依赖
在 pom.xml 中引入 Redis 和 Spring Cache 相关依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
2.2 配置 Redis 连接
在 application.yml 中,配置 Redis 服务器地址及相关连接池配置:
spring:cache:type: redis # 使用 Redis 作为缓存类型data:redis:host: localhostport: 6379 # Redis 端口password: # 如果有密码可以在这里配置lettuce:pool:max-active: 100 # 最大并发连接数max-idle: 50 # 最大空闲连接数min-idle: 10 # 最小空闲连接数
2.3 启用缓存支持
在 Spring Boot 项目中,使用 @Cacheable 注解前,需要通过 @EnableCaching 注解启用缓存功能。可以在主应用类或者任何配置类中加上这个注解:
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@EnableCaching
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
3. 注解驱动的缓存机制
Spring 提供了一组注解用于操作缓存,这些注解可以直接应用于方法上,使得代码更简洁。常用注解包括:
@Cacheable:用于标记一个方法的返回值是可缓存的。下一次调用该方法时,Spring 会直接从缓存中返回结果,而不是再次执行方法。@CachePut:在方法执行后将返回值放入缓存。它与@Cacheable的区别在于,@CachePut不会跳过方法执行,而是始终执行方法并更新缓存。@CacheEvict:用于清除缓存中的某些条目,可以指定缓存的 key 或清空整个缓存空间。
3.1 @Cacheable示例
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;@Service
public class UserService {// 当方法第一次调用时,结果将被缓存起来,之后相同参数的调用将直接从缓存中获取数据@Cacheable(value = "user", key = "#p0")public User getUserById(Long id) {// 模拟数据库查询操作System.out.println("Fetching user with id: " + id);return new User(id, "User" + id);}
}
解释:
@Cacheable用于缓存方法的返回值。value = "user"指定了缓存的名称,即 “user”。key = "#p0"指定了缓存的键值。这里的#p0是一个 SpEL 表达式,表示方法的第一个参数。
在这个例子中,方法 getUserById 第一次被调用时,结果会缓存到 Redis 中,并与 user::id 作为 key 存储。后续相同 id 的请求将直接从缓存返回,而无需执行方法。

3.2 @CachePut示例
有时候,我们希望方法执行后,不仅返回结果,还更新缓存,这时可以使用 @CachePut 注解。
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;@Service
public class UserService {// 无论缓存中是否存在数据,该方法都会被执行,并且返回值会更新缓存@CachePut(value = "user", key = "#p0.id")public User updateUser(User user) {System.out.println("Updating user with id: " + user.getId());// 模拟数据库更新操作user.setName("Updated " + user.getName());return user;}
}
解释:
@CachePut用于更新缓存中的值。value = "user"指定了缓存的名称,即 “user”。key = "#p0.id"指定了缓存的键值。这里的#p0是一个 SpEL 表达式,表示方法的第一个参数,即User对象。.id表示取User对象的id属性作为缓存键。
连续两次调用 curl "http://localhost:8080/api/redis/updAndSave?id=2" ,可以从日志中看到,每次方法都执行了,并且 user 对象加入到了缓存中。

3.3 @CacheEvict示例
为了保持缓存数据的准确性,某些情况下需要手动清除缓存中的数据。@CacheEvict 注解允许我们在数据修改或删除时,移除缓存中的旧数据。
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;@Service
public class UserService {// 清除缓存中的指定用户数据@CacheEvict(value = "user", key = "#p0")public void deleteUser(Long id) {System.out.println("Deleting user with id: " + id);// 模拟数据库删除操作}// 清空整个缓存空间@CacheEvict(value = "user", allEntries = true)public void clearCache() {System.out.println("Clearing all user cache");}
}
调用 curl "http://localhost:8080/api/redis/delUser?id=1" ,删除 key 为 user::1 的缓存。

调用 curl "http://localhost:8080/api/redis/delAllUser" ,删除所有前缀为 user:: 的缓存。

4. 自定义缓存管理
以上缓存名称、过期时间和序列化方式都是默认设置,Spring 允许我们自定义缓存管理器。在大多数情况下,默认配置足够使用,但如果需要定制化的缓存行为,我们可以自定义缓存配置。通过实现 RedisCacheConfiguration,我们可以设置缓存的过期时间、序列化方式等。
4.1 RedisCacheConfiguration 类
Spring Boot 3 中,RedisCacheConfiguration 类是用于配置 Redis 缓存行为的核心组件之一。它提供了多种方法,用于自定义 Redis 缓存的各类设置,比如缓存过期时间、序列化策略等。以下是一些常用的配置选项:
4.1.1. 过期时间(TTL - Time To Live)
设置缓存条目的默认生存时间(TTL)。这决定了缓存数据在 Redis 中保留的时间。
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)); // 设置缓存10分钟后过期
4.1.2. 键序列化方式
默认情况下,Redis 使用二进制存储键和值。RedisCacheConfiguration 提供了设置键(key)序列化方式的方法。常见的序列化方式包括 StringRedisSerializer,可以使用它来确保键以字符串格式存储:
import org.springframework.data.redis.serializer.StringRedisSerializer;RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
4.1.3. 值序列化方式
同样,值(value)的序列化方式也可以自定义。常用的序列化方式有 GenericJackson2JsonRedisSerializer,它将对象序列化为 JSON 格式:
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
4.1.4. 禁用缓存空值(Disable Caching Null Values)
你可以配置不缓存空值,避免 Redis 存储 null,减少缓存的无效占用。
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues();
4.1.5. 使用前缀(Use Cache Key Prefixes)
Redis 中默认会为缓存键值加上一个命名空间的前缀,以防止不同缓存键冲突。可以自定义这个前缀,也可以关闭它:
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().prefixCacheNameWith("myApp::") // 自定义缓存键前缀.computePrefixWith(cacheName -> "customPrefix::" + cacheName + "::"); // 使用自定义逻辑
要禁用前缀:
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().disableKeyPrefix();
4.1.6. 设置空闲时间(Idle Time)
你可以设置一个键的空闲时间,Redis 将会在指定的时间内删除不再被访问的键。
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)).enableTimeToIdle();
4.1.7. 组合多种配置
可以将多个配置组合到一起:
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;import java.time.Duration;@Configuration
public class CacheConfig {@Beanpublic RedisCacheConfiguration redisCacheConfiguration() {return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 缓存的过期时间.disableCachingNullValues() // 不缓存 null 值.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 自定义 key 序列化.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); // 自定义 value 序列化}
}
4.1.8. 设置自定义的过期策略
可以为不同的缓存区域设置不同的过期策略。例如:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;@Configuration
public class CacheConfig {@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5));RedisCacheConfiguration longLivedConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();cacheConfigurations.put("shortLivedCache", defaultConfig);cacheConfigurations.put("longLivedCache", longLivedConfig);return RedisCacheManager.builder(connectionFactory).withInitialCacheConfigurations(cacheConfigurations).build();}
}
4.2 自定义缓存配置
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.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;import java.time.Duration;@Configuration
public class CacheConfig {@Beanpublic RedisCacheConfiguration cacheConfiguration() {return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 设置缓存过期时间为 10 分钟.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) // 自定义 Key 序列化器.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); // 自定义 Value 序列化器}
}
通过这种方式,我们可以对缓存的过期时间、序列化方式进行更细粒度的控制。

5. Redis 缓存的常见问题和优化建议
尽管 Redis 是一个高效的缓存解决方案,但在实际应用中,仍然有一些需要注意的问题:
- 缓存穿透:大量请求查询缓存中不存在的 key,导致所有请求都直接打到数据库上,降低系统性能。解决方案是使用布隆过滤器来拦截非法请求。
- 缓存雪崩:当大量缓存同时过期时,可能会导致瞬间的大量请求直接涌入数据库,造成系统崩溃。可以通过设置不同的过期时间(TTL)来缓解这一问题。
- 缓存击穿:某个热点 key 在缓存过期后,大量并发请求直接打到数据库上。解决方案是使用互斥锁,避免大量请求同时加载缓存。
6. 总结
通过本文,我们学习了如何在 Spring Boot 3 和 Java 17 中使用 Redis 作为缓存。Spring 提供了注解驱动的缓存操作方式,使得缓存操作变得非常简单易用。通过合理配置和使用缓存,我们能够极大地提升系统的性能和响应速度。在生产环境中,合理的缓存策略、过期时间和缓存层优化将会进一步提高系统的稳定性和扩展能力。
相关文章:
重学SpringBoot3-集成Redis(二)之注解驱动
更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-集成Redis(二)之注解驱动 1. 为什么选择 Redis 作为缓存?2. 如何在 Spring Boot 中启用 Redis 缓存?2.1 …...
【React】入门Day04 —— 项目搭建及登录与表单校验、token 管理、路由鉴权实现
项目搭建 创建项目 # 使用npx创建项目 npx create-react-app my-react-app # 进入项目目录 cd my-react-app # 创建项目目录结构 mkdir -p src/{apis,assets,components,pages,store,utils} touch src/{App.js,index.css,index.js} 使用npx create-react-app创建项目࿰…...
CMake 属性之目录属性
【写在前面】 CMake 的目录属性是指在特定目录(及其子目录)范围内有效的设置。 这些属性不同于全局变量或目标(Target)属性,它们提供了一种机制,允许开发者为项目中的不同部分定义不同的构建行为。 通过目录…...
ChatGPT:引领人工智能新潮流!
一、ChatGPT 是什么? 1. ChatGPT 的强大功能和广泛应用。 ChatGPT 作为一款先进的 AI 语言模型,拥有众多强大功能。它可以进行文本生成、文本分类、情感分析、机器翻译等多种自然语言处理任务。同时,ChatGPT 还能进行对话式交互,…...
【银河麒麟高级服务器操作系统】安全配置基线相关分析全过程及解决方案
了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer.kylinos.cn 文档中心:https://documentkylinos.cn 服务器环境以及配置 【机型】物理机或虚机 【…...
用Python实现图片转ASCII艺术:图像处理与字符艺术的完美结合
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 ASCII艺术是一种通过字符来表现图像的艺术形式,最早用于早期计算机显示器,它仅支持字符显示。如今,尽管图像分辨率和显示技术得到了极大的提升,ASCII艺术作为一种复古而别具一格的图像表现形式,仍然受到许多…...
大数据-162 Apache Kylin 全量增量Cube的构建 Segment 超详细记录 多图
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...
Redis-缓存过期淘汰策略
缓存淘汰策略 生产上redis内存设置为多少 设置为最大内存的 3/4 redis 会占用物理机多少内存 默认大小是 0,64 位系统下表示不限制内存大小,32位系统表示 3G 如何设置修改redis内存大小 config get maxmemory 查看修改方式 配置文件 单位是字节 2.…...
如何设置LED电子显示屏的屏幕参数?
LED电子显示屏因其高亮度、低能耗和长寿命等优点,在广告、信息显示等领域得到了广泛应用。正确设置屏幕参数对于确保显示屏的最佳性能至关重要。以下是LED电子显示屏设置屏幕参数的步骤: 1. 确定屏幕参数 在开始设置之前,需要了解显示屏的基本…...
Spring Boot Starter Parent介绍
引言 spring-boot-starter-parent 是一个特殊的项目,为基于 Spring Boot 的应用程序提供默认配置和默认依赖。 在本 Spring Boot 教程中,我们将深入了解所有 Spring Boot 项目内部使用的 spring-boot-starter-parent 依赖项。我们将探讨此依赖项所提供…...
【含开题报告+文档+PPT+源码】基于SpringBoot乡村助农益农平台的设计与实现
开题报告 近年来,随着社会经济的快速发展和人民生活水平的提高,人们对优质农产品的需求越来越高。然而,传统的农产品销售管理模式存在一些问题。首先,农产品供应链信息不透明,导致生产者难以了解市场需求和价格变动趋…...
数据中心运维挑战:性能监控的困境与智能化解决方案的探寻
随着数字化进程的加速,数据中心已成为企业信息架构的核心支撑,其运维管理的复杂度和重要性也随之提升。运维团队需应对设备老化、资源分配失衡、性能波动等多重难题,以确保数据中心持续高效运行。 其中,性能监控作为运维管理的关键…...
基于SSM的民宿管理系统【附源码】
基于SSM的民宿管理系统(源码L文说明文档) 目录 4 系统设计 4.1 系统概要设计 4.2 系统功能结构设计 4.3 数据库设计 4.3.1 数据库E-R图设计 4.3.2 数据库表结构设计 5 系统实现 5.1用户信息管理 5.2 房东信息管理…...
显卡 3090 vs v100
1.3090 Date: 2020 AmperePielines/ Cuda cores: 10496 2.V100 Date: 2018 VoltaPielines/ Cuda cores: 5129 3.结构 & Core比较: v100优点: v100功耗小v100较快的双精度(fp64)和混合精度(fp16fp32)pcie版的NVLink与2080ti完全一致 v100缺点: 不支持整数格式计算&…...
怎么在单片机裸机程序中移植EasyLogger?
1、介绍 EasyLogger 是一款超轻量级、高性能的C日志库,非常适合对资源敏感的软件项目。例如:IoT产品、可穿戴设备、智能家居等等。相比log4c、zlog这些知名的C日志库,EasyLogger的功能更加简单,提供给用户的接口更少,但…...
C/C++解析文件名和目录路径
文章目录 主要函数使用注意事项示例程序总结 #include <libgen.h> 是一个 C/C 语言的头文件,主要用于字符串处理,特别是在处理文件路径时。它提供了一些函数来帮助你解析文件名和目录路径。 主要函数 以下是 libgen.h 中一些常见的函数ÿ…...
Git 基本命令行操作
Git是一个开源的分布式版本控制系统,用于管理源代码和文档的版本。以下是Git的基本命令行操作: 一、配置 安装完成后,需要配置Git的用户名和邮箱,以便在提交记录时记录操作者的信息。 配置全局用户名:git config --g…...
【Rust练习】17.泛型
练习题来自:https://practice-zh.course.rs/generics-traits/generics.html 函数 1 // 填空 struct A; // 具体的类型 A. struct S(A); // 具体的类型 S. struct SGen<T>(T); // 泛型 SGen.fn reg_fn(_s: S) {}fn gen_spec_t(_s: SGen<A&…...
java脚手架系列4--测试用例、拦截器
异常处理、拦截器、数据库连接 1 测试用例 单元测试是一个老生常谈的问题,无论是后端对自己的代码质量把的第一道关也好,也是对测试减缓压力。这里就不过多讲述测试用例的重要性,但是有2个框架我们必须了解一下。 1.1 JUnit和mockito 我们…...
论文推荐 |【Agent】自动化Agent设计系统
论文标题: Automated Design of Agentic Systems 论文地址: https://arxiv.org/abs/2408.08435 GitHub地址: https://github.com/ShengranHu/ADAS 自动化代理设计在性能和通用性方面显著超越了手动方法。 • 引入了自动化代理系统设计&am…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
