Spring Boot 4.0 整合 Redis:缓存设计与序列化方案
前言
订单查询接口先查 Redis,未命中再查订单服务,这是最常见的缓存读路径。真正容易出错的不是 opsForValue().set(),而是 Key 如何命名、值如何序列化、TTL 多长,以及 Redis 故障时接口是否还能工作。
这篇教程会在现有订单项目中增加读穿缓存。完成后可以观察缓存回填、直接读取 Redis 中的 JSON,并验证 TTL。
配套源码:dvsusan/spring-boot4-demo。
最终结果

图 1:读穿缓存先查 Redis,未命中才加载订单并回填。
项目中的实现位于 demo-integration,默认关闭,避免前面章节强制依赖 Redis。
第 1 步:启动 Redis
项目已经提供 Docker Compose:
docker compose up -d redis
docker compose ps redis预期状态为 running。如果 Docker 守护进程没有启动,先启动 Docker Desktop。
测试连接:
docker compose exec redis redis-cli PING预期输出:
PONG第 2 步:使用统一的 JSON 缓存服务
核心代码:
/**
* 订单缓存读写服务。
*
* <p>缓存值统一使用 JSON 字符串,避免 Java 原生序列化带来的兼容和安全问题。</p>
*/
public class OrderCacheService {
private final StringRedisTemplate redis;
private final ObjectMapper objectMapper;
private final Duration ttl;
public OrderView getOrLoad(String orderNo, Supplier<OrderView> loader) {
String key = "chapter4:order:" + orderNo;
String cached = redis.opsForValue().get(key);
if (cached != null) {
return objectMapper.readValue(cached, OrderView.class);
}
OrderView order = loader.get();
redis.opsForValue().set(
key,
objectMapper.writeValueAsString(order),
ttl
);
return order;
}
}这里使用 Spring Boot 4 默认的 Jackson 3 ObjectMapper。缓存中存 JSON,其他语言、命令行和调试工具都能读取;不要使用 Java 原生序列化。
Key 统一加业务前缀,后续可按 chapter4:order:* 统计和清理。每次写入必须同时设置 TTL,防止异常数据永久占用内存。
第 3 步:开启缓存并启动应用
mvn clean package -DskipTests
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar \
--server.port=18091 \
--demo.chapter4.redis.enabled=true \
--demo.chapter4.redis.ttl=5m先创建订单:
curl -X POST "http://localhost:18091/api/v1/orders" \
-H "Content-Type: application/json" \
-d '{"customerId":"C1001","amount":99.00}'把返回的 orderNo 代入下一次请求:
curl "http://localhost:18091/api/v1/chapter4/cache/orders/SO..."
curl "http://localhost:18091/api/v1/chapter4/cache/orders/SO..."两次都能返回订单。第一次可能加载并回填,第二次通常直接读取缓存。
第 4 步:检查缓存内容
docker compose exec redis redis-cli \
GET "chapter4:order:SO..."
docker compose exec redis redis-cli \
TTL "chapter4:order:SO..."第一条返回 JSON 字符串,第二条返回剩余秒数。TTL 不增长,说明没有在每次命中时无条件延长缓存寿命。
Redis 故障时怎么办?
缓存是加速层,不应成为订单查询的唯一数据源。生产项目要明确选择:
| 策略 | 行为 | 适用场景 |
|---|---|---|
| Fail fast | Redis 异常直接报错 | 强依赖低延迟一致性缓存 |
| Fail open | 捕获异常后查数据库 | 缓存主要承担加速 |
| 本地兜底 | 使用短期本地缓存 | 热点读、可接受短时旧值 |
无论采用哪种策略,都要记录 Redis 异常、超时和降级次数,不能静默吞掉。
常见问题排查
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 连接被拒绝 | Redis 未启动或端口错 | 检查 docker compose ps 和端口 |
| JSON 反序列化失败 | 类结构升级但旧缓存仍存在 | 加版本前缀或按 Key 清理 |
| 缓存一直不命中 | Key 拼接不一致 | 统一 Key 构造函数 |
TTL 为 -1 | 写入时没有过期时间 | 强制所有写缓存入口传 TTL |
| Redis 故障拖垮查询 | 没有超时和降级 | 设置连接超时并定义 fail-open |
练习题
增加 chapter4:order:v2: 前缀,并验证旧版本缓存不会被新代码读取。
验收标准:新旧 Key 可以同时存在,回滚代码后仍能识别旧版本。
总结
Redis 缓存的核心不是一条读写命令,而是完整的数据生命周期:统一 Key、JSON 序列化、明确 TTL、故障降级和可观测性。
下一篇处理更棘手的问题:数据库更新成功后,缓存应该怎样失效。
13 个企业级实战项目 · 源码 + 教程 + 答疑
简历包装指导AI Agent 实战高并发·微服务Offer 导向持续更新3000+ 同行交流1V1 答疑3 天包退
覆盖高并发、微服务、分布式与 AI Agent:100万QPS短链、企业智能知识库、商城微服务、SaaS点餐、秒杀、刷题小程序、代码生成器、AI Agent 等。券后 ¥129(原价 ¥159),不满意 3 天包退。
