Spring Boot 4.0 分布式锁:Redisson 原理与常见坑
2026-11-07Spring Boot 4.0Spring Boot 4Redisson
前言
两个请求同时处理同一订单,可能重复退款、重复发货或覆盖状态。单机 synchronized 只能约束一个 JVM,多实例部署时就需要跨进程互斥。
这篇教程用 Redisson 的 RLock 建立订单锁,并验证只有持锁线程才能释放锁。
配套源码:dvsusan/spring-boot4-demo。
最终结果

图 1:获取锁后执行业务,finally 中只释放当前线程持有的锁。
第 1 步:启动 Redis
docker compose up -d redis
docker compose exec redis redis-cli PING预期返回 PONG。
第 2 步:创建 Redisson 客户端
// 应用关闭时释放 Redisson 的连接和后台线程。
@Bean(destroyMethod = "shutdown")
public RedissonClient redissonClient(
@Value("${demo.chapter4.redisson.address:redis://127.0.0.1:6379}")
String address
) {
Config config = new Config();
config.useSingleServer().setAddress(address);
return Redisson.create(config);
}destroyMethod="shutdown" 保证应用关闭时释放连接和内部线程。
第 3 步:把锁边界写在业务代码外
public <T> T execute(String orderNo, Duration waitTime, Supplier<T> action) {
RLock lock = redissonClient.getLock("chapter4:lock:order:" + orderNo);
boolean locked = false;
try {
// -1 使用 Watchdog 自动续期,避免业务未结束锁先过期。
locked = lock.tryLock(waitTime.toMillis(), -1, TimeUnit.MILLISECONDS);
if (!locked) {
throw new IllegalStateException("订单正在处理,请稍后重试");
}
return action.get();
} finally {
if (locked && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}isHeldByCurrentThread() 防止线程 A 的锁超时后被线程 B 获取,A 又把 B 的锁删掉。
第 4 步:运行并调用
mvn clean package -DskipTests
java -jar demo-web/target/demo-web-1.0.0-SNAPSHOT.jar \
--server.port=18093 \
--demo.chapter4.redisson.enabled=truecurl -X POST \
"http://localhost:18093/api/v1/chapter4/locks/orders/SO1001"预期:
{"code":"0","data":"lock acquired for SO1001"}可以并行运行两条请求观察等待和竞争。锁粒度应覆盖完整的不变量,而不是只锁一行 get 或 set。
Watchdog 和 leaseTime 怎么选?
leaseTime=-1:启用 Watchdog,业务存活期间自动续期。- 固定
leaseTime:到期强制释放,适合能明确保证最大执行时间的任务。 - 等待时间
waitTime:控制客户端愿意排队多久。
固定租期过短会导致业务未完成锁已释放;Watchdog 也不能解决 Redis 整体不可用或主从切换。
常见问题排查
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 锁一直不释放 | 异常路径没有 finally | 封装统一执行模板 |
| 报错“锁被其他线程持有” | 误删其他线程锁 | 判断 isHeldByCurrentThread |
| 同一线程无法再次进入 | 误以为锁不可重入 | RLock 本身支持重入 |
| 主从切换后出现双持有 | 异步复制丢锁 | 高风险操作使用数据库约束或 fencing token |
| 持锁后接口很慢 | 锁内包含远程调用 | 缩小锁范围,避免锁内 I/O |
练习题
给锁增加业务唯一 requestId,在锁内执行前查询幂等表,重复请求直接返回。
总结
分布式锁解决互斥,不解决消息和远程调用的全部一致性问题。最小的锁边界、唯一释放和异常兜底,比堆 Redis 配置更重要。
下一篇进入异步解耦:用 RocketMQ 发布订单事件。
13 个企业级实战项目 · 源码 + 教程 + 答疑
简历包装指导AI Agent 实战高并发·微服务Offer 导向持续更新3000+ 同行交流1V1 答疑3 天包退
覆盖高并发、微服务、分布式与 AI Agent:100万QPS短链、企业智能知识库、商城微服务、SaaS点餐、秒杀、刷题小程序、代码生成器、AI Agent 等。券后 ¥129(原价 ¥159),不满意 3 天包退。
