全网最全!Spring Boot 分布式锁从入门到实战(5 种方案 + 秒杀场景 + 完整源码)
🎯 全网最全!Spring Boot 分布式锁从入门到实战(5 种方案 + 秒杀场景 + 完整源码)
一个通俗易懂的 Spring Boot 分布式锁学习项目,5 种锁方案、真实业务场景、1400+ 行详细文档,手把手教你从理论到生产实践!
📢 写在前面
作为一名 Java 开发者,你是否遇到过这些问题:
😱 真实踩坑场景
场景 1:秒杀库存扣成负数
库存 100 件,1000 人同时抢
结果:卖出 150 件,库存变成 -50
老板:谁干的?!
场景 2:定时任务重复执行
3 台服务器同时执行"每日结算"
结果:用户被扣了 3 次钱
客服:电话被打爆了
场景 3:订单重复提交
用户手抖点了 3 次"支付"
结果:同一笔订单扣了 3 次款
财务:账对不上了
根本原因:单机锁(synchronized)在分布式环境下失效了!
🌟 项目亮点
| 亮点 | 说明 |
|---|---|
| ✅ 5 种锁方案 | Redis、Redisson、Redlock、Zookeeper、数据库锁全覆盖 |
| ✅ 通俗易懂 | 生活化比喻(厕所门锁、商场储物柜),小白也能懂 |
| ✅ 真实场景 | 秒杀扣库存、防重复提交、定时任务防重 |
| ✅ 最佳实践 | 工业级四层防护机制,可直接用于生产 |
| ✅ 代码简洁 | 不使用 Lambda,步骤清晰,注释详细 |
| ✅ 完整文档 | 1400+ 行 README,CAP/BASE 理论详细讲解 |
🚀 快速开始
环境要求
- JDK 8+
- MySQL 8.0+
- Redis 5.0+
一键启动
# 1. 克隆项目
git clone https://gitcode.com/lipansfj/distributed-lock-learning.git
# 2. 修改数据库配置(application.yml)
spring:
datasource:
url: jdbc:mysql://localhost:3306/distributed_lock_db
username: root
password: your_password
# 3. 运行项目
mvn clean spring-boot:run
# 4. 访问 API 文档
# http://localhost:8080/doc.html
📚 项目全景图
核心模块
distributed-lock-learning/
├── 5 种锁方案实现
│ ├── SimpleLockService # Redis 基础锁(学习原理)
│ ├── RedissonLockService # Redisson 看门狗锁(生产推荐)
│ ├── RedlockService # Redlock 算法(高可用)
│ ├── ZkLockService # Zookeeper 锁(强一致性)
│ └── DatabaseLockService # 数据库锁(简单场景)
│
├── 3 个业务场景
│ ├── SeckillController # 秒杀扣库存
│ ├── OrderController # 防重复提交
│ └── LockDemoController # 锁演示接口
│
├── 混合策略
│ └── HybridLockService # 根据优先级选锁
│
└── 完整文档
└── README.md # 1400+ 行详细教程
💡 核心理论(一句话记住)
CAP 理论
口诀:分布式系统,P 必须选,C 和 A 只能选一个
生活化比喻:就像"快、好、省"只能三选二
场景演示:
假设:北京和上海两个银行节点,网络断了
选择 CP(一致性 + 分区容错):
→ 暂停服务,保证数据一致
→ ✅ 数据正确 ❌ 不可用
→ 适用:银行转账、库存扣减
选择 AP(可用性 + 分区容错):
→ 继续服务,允许短暂不一致
→ ✅ 可用 ⚠️ 数据可能不一致
→ 适用:微信点赞、Redis 缓存
BASE 理论
口诀:基本可用,允许中间状态,最终会一致
秒杀订单案例:
T=0ms: 用户点击"立即购买"
T=10ms: 订单创建,返回"下单成功" ✅ (基本可用)
T=11ms: 订单状态: PROCESSING ⚠️ (软状态)
T=2s: 库存扣减完成,状态: SUCCESS ✅ (最终一致)
用户感知:立即看到成功(体验好)
后台处理:异步扣库存(高性能)
🛠️ 5 种分布式锁方案对比
| 方案 | 可靠性 | 性能 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| Redis 基础锁 | ⭐⭐ | ⭐⭐⭐⭐⭐ | 低 | 学习原理 |
| Redisson 看门狗 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 中 | 生产推荐 |
| Redlock | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 高 | 高可用要求 |
| Zookeeper | ⭐⭐⭐⭐⭐ | ⭐⭐ | 中 | 强一致性 |
| 数据库锁 | ⭐⭐⭐⭐ | ⭐ | 低 | 低并发 |
💻 核心代码实战
方案 1:Redis 基础锁(理解原理)
核心方法:
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, 10, TimeUnit.SECONDS);
完整实现(简单易懂):
// 步骤1:尝试获取锁
String requestId = simpleLockService.tryLock(lockKey, 10);
if (requestId == null) {
return false; // 获取锁失败
}
try {
// 步骤2:执行业务逻辑
doBusiness();
} finally {
// 步骤3:释放锁(必须验证拥有者)
simpleLockService.releaseLock(lockKey, requestId);
}
⚠️ 常见错误:
// ❌ 错误1:不设置过期时间 → 死锁
redisTemplate.opsForValue().setIfAbsent(key, value);
// ❌ 错误2:分开设置值和过期时间 → 非原子操作
redisTemplate.opsForValue().set(key, value);
redisTemplate.expire(key, 10, TimeUnit.SECONDS);
// ❌ 错误3:不验证锁的拥有者 → 误删别人的锁
redisTemplate.delete(key);
方案 2:Redisson 看门狗锁(生产推荐)⭐
核心问题:锁设置 10 秒过期,但业务需要执行 20 秒,怎么办?
传统锁的问题:
T=0s: 线程A获取锁,设置10秒过期
T=10s: ⚠️ 锁自动释放,线程B也能获取锁
T=10-20s: 线程A和B同时执行 ❌ 并发安全问题!
Redisson 看门狗解决方案:
T=0s: 线程A获取锁,看门狗启动(默认30秒)
T=10s: 看门狗检查 → 还持有锁 → 自动续期30秒
T=20s: 看门狗检查 → 还持有锁 → 再次续期30秒
T=50s: 业务完成,调用unlock(),停止看门狗
代码实现(简单 4 步):
// 步骤1:先获取锁
boolean locked = redissonLockService.tryLock(lockKey, 3, 10);
if (!locked) {
// 获取锁失败,立即返回
return ApiResponse.fail("获取锁超时");
}
try {
// 步骤2:执行业务逻辑
log.info("获取锁成功,开始执行业务逻辑...");
// 模拟业务处理(比如查询数据库、调用接口等)
Thread.sleep(2000);
// 步骤3:返回业务结果
result.put("success", true);
result.put("message", "业务执行成功");
} catch (InterruptedException e) {
// 异常处理
result.put("success", false);
result.put("message", "业务执行被中断");
} finally {
// 步骤4:释放锁(无论成功还是失败都要释放)
redissonLockService.unlock(lockKey);
log.info("锁已释放");
}
优势:
- ✅ 自动看门狗续期,不会提前过期
- ✅ 支持可重入锁(同一线程可多次获取)
- ✅ 一行代码搞定,代码简洁
方案 3:混合锁策略(智能选择)
根据业务优先级自动选择锁:
// 高优先级:使用 Zookeeper(强一致性)
hybridLockService.executeWithPriority(
LockPriority.HIGH,
lockKey,
() -> criticalBusiness()
);
// 中优先级:使用 Redlock(平衡性能和可靠性)
hybridLockService.executeWithPriority(
LockPriority.MEDIUM,
lockKey,
() -> normalBusiness()
);
// 低优先级:使用 Redisson(高性能)
hybridLockService.executeWithPriority(
LockPriority.LOW,
lockKey,
() -> commonBusiness()
);
🔥 真实业务场景
场景 1:秒杀扣库存(四层防护)
@Transactional
public Result seckill(Long productId, Long userId) {
RLock lock = redisson.getLock("seckill:" + productId);
try {
// 第1层:Redis 分布式锁(拦截 99% 并发)
boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
if (!locked) {
return Result.fail("系统繁忙");
}
// 第2层:检查库存/业务规则
Stock stock = stockMapper.selectById(productId);
if (stock.getCount() <= 0) {
return Result.fail("库存不足");
}
// 第3层:数据库乐观锁(版本号控制)
int affected = stockMapper.decreaseWithVersion(productId);
if (affected == 0) {
return Result.fail("库存不足");
}
// 第4层:数据库唯一约束(防止重复购买)
try {
orderMapper.insert(productId, userId);
} catch (DuplicateKeyException e) {
return Result.fail("请勿重复购买");
}
return Result.success();
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
四层防护机制:
- Redis 锁:拦截 99% 并发请求
- 库存检查:快速失败,减少数据库压力
- 乐观锁:版本号控制,防止并发更新
- 唯一约束:数据库兜底,防止重复购买
场景 2:防重复提交
@PostMapping("/create")
public Result createOrder(@RequestBody OrderRequest request) {
// 使用用户ID + 商品ID作为锁
String lockKey = "order:create:" + request.getUserId()
+ ":" + request.getProductId();
boolean locked = redissonLockService.tryLock(lockKey, 3, 10);
if (!locked) {
return Result.fail("请勿重复提交");
}
try {
// 创建订单
orderService.create(request);
return Result.success("订单创建成功");
} finally {
redissonLockService.unlock(lockKey);
}
}
📊 性能对比数据
| 方案 | RT(响应时间) | QPS | 性能下降 |
|---|---|---|---|
| Redis 普通锁 | 1-5ms | 8000+ | - |
| Redisson 锁 | 1-5ms | 8000+ | - |
| Redlock | 5-10ms | 2000-3000 | ↓ 70% |
| Zookeeper | 10-50ms | 1000-2000 | ↓ 80% |
| 数据库锁 | 100-500ms | < 1000 | ↓ 90% |
选型建议:
- 90% 的场景:Redisson + 数据库兜底
- 金融级场景:Zookeeper 或 etcd
- 低并发场景:数据库乐观锁即可
- 永远不要:只依赖一层防护
🎯 适用人群
| 人群 | 能获得什么 |
|---|---|
| 🎓 初学者 | 系统学习分布式锁,从理论到实践 |
| 💼 中级开发 | 应对面试,掌握生产级方案 |
| 👨 高级开发 | 参考最佳实践和架构设计 |
| 📚 培训讲师 | 完整的教学材料和案例 |
📦 项目结构
distributed-lock-learning/
├── src/main/java/
│ ├── config/ # 配置类
│ │ ├── RedissonConfig.java # Redisson 配置
│ │ ├── ZookeeperConfig.java # Zookeeper 配置
│ │ └── Knife4jConfig.java # API 文档配置
│ │
│ ├── controller/ # REST API
│ │ ├── LockDemoController.java # 锁演示接口
│ │ ├── SeckillController.java # 秒杀接口
│ │ └── OrderController.java # 订单接口
│ │
│ ├── service/ # 业务逻辑
│ │ ├── SimpleLockService.java # Redis 基础锁
│ │ ├── RedissonLockService.java # Redisson 看门狗锁
│ │ ├── RedlockService.java # Redlock 算法
│ │ ├── ZkLockService.java # Zookeeper 锁
│ │ ├── DatabaseLockService.java # 数据库锁
│ │ └── HybridLockService.java # 混合策略
│ │
│ ├── entity/ # 实体类
│ │ ├── Stock.java # 库存表
│ │ ├── Orders.java # 订单表
│ │ └── DistributedLock.java # 锁记录表
│ │
│ ├── mapper/ # MyBatis Mapper
│ ├── dto/ # 数据传输对象
│ └── common/ # 通用工具类
│
├── src/main/resources/
│ ├── application.yml # 配置文件
│ └── schema.sql # 数据库建表脚本
│
└── README.md # 1400+ 行完整文档
学习路线图
第一阶段:为什么需要分布式锁?
└─ 单机锁的局限性(synchronized 失效)
第二阶段:理论基础
└─ CAP 理论 + BASE 理论
第三阶段:基础实现
└─ Redis setIfAbsent() 原子操作
第四阶段:生产级方案
└─ Redisson 看门狗锁(自动续期)
第五阶段:高级方案
├─ Redlock(多节点高可用)
├─ Zookeeper(强一致性)
└─ 数据库锁(简单场景)
第六阶段:最佳实践
└─ 多层防护机制(四层防护)
📝 常见问题
Q1: 为什么不直接用 synchronized?
A: synchronized 是 JVM 级别的锁,只能在单个进程中生效。分布式环境下有多个服务器,synchronized 无法跨进程互斥。
生活化比喻:
synchronized= 家里厕所的门锁(只有自己家人能用)- 分布式锁 = 商场公共厕所的门锁(所有人都能看到是否有人)
Q2: Redis 锁可靠吗?会不会丢锁?
A: Redis 锁在主从切换时可能丢锁,但概率较低(约 1-5%/年)。对于 90% 的业务场景,Redis 锁 + 数据库兜底已经足够可靠。
建议:
- 非关键业务:Redis 锁即可
- 关键业务:Redis 锁 + 数据库乐观锁 + 唯一约束(多层防护)
- 金融级业务:Zookeeper
Q3: 锁的超时时间应该设置多久?
A: 根据业务耗时的 1.5-2 倍 设置。
示例:
- 业务平均耗时 3 秒 → 锁超时设置为 5-6 秒
- 业务平均耗时 100ms → 锁超时设置为 150-200ms
注意:如果使用 Redisson,可以启用看门狗机制,自动续期锁。
Q4: 项目可以直接用于生产吗?
A: 可以!项目包含了生产级的多层防护方案,Redisson 看门狗锁已在多个实际项目中使用。
🚀 如何获取
项目地址:https://gitcode.com/lipansfj/distributed-lock-learning.git
# 克隆项目
git clone https://gitcode.com/lipansfj/distributed-lock-learning.git
# 进入项目目录
cd distributed-lock-learning
# 运行项目
mvn clean spring-boot:run
# 访问 API 文档
# http://localhost:8080/doc.html
⭐ 如果觉得有帮助
如果这个项目对你有帮助,请:
- 给项目一个 Star ⭐
- 分享给需要的朋友 📢
- 应用到实际项目中 💪
你的支持是我持续更新的动力!🙏
📮 联系方式
- 项目地址:https://gitcode.com/lipansfj/distributed-lock-learning.git
- 问题反馈:欢迎提 Issue 或 PR
- 技术交流:欢迎 Fork 和 Star
💡 温馨提示:如果觉得这篇文章对你有帮助,请点赞、收藏、转发,让更多人看到!
关注我,获取更多 Java 实战项目和经验分享!🚀
更多推荐


所有评论(0)