Java + MySQL + Redis 构建高并发秒杀系统实战(乐观锁/悲观锁/接口限流)
下面给你一套非常硬核、毕设/面试双杀的方案:
《基于 Java + MySQL + Redis 的高并发秒杀系统实战》
✅ 支持 乐观锁 / 悲观锁 / Redis 预减库存 / 接口限流
✅ 技术深度够,答辩老师基本不会为难你
✅ 可以直接当 毕设 / 课程设计 / 技术博客 / 面试项目

一、业务场景
以「商品秒杀」为例:
-
商品库存:100 件
-
瞬时并发:10000+ 请求
-
核心问题:
-
超卖(库存 < 0)
-
重复下单
-
数据库被打爆
-
接口被刷
-
二、技术架构
客户端
↓
Nginx(负载均衡)
↓
SpringBoot
├── 接口限流(Redis + Lua)
├── 秒杀接口
│ ├── Redis 预减库存
│ └── MQ 异步下单(可选)
├── 库存回滚
↓
MySQL(订单 / 商品)
Redis(缓存 + 计数 + 限流)
|
技术 |
作用 |
|---|---|
|
SpringBoot |
快速开发 |
|
Redis |
缓存、预减库存、限流 |
|
MySQL |
持久化 |
|
MyBatis |
ORM |
|
Redisson / Lua |
分布式锁 |
|
RabbitMQ(可选) |
异步削峰 |
三、数据库设计(极简但够用)
1️⃣ 商品表 seckill_product
CREATE TABLE seckill_product (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
stock INT,
price DECIMAL(10,2),
start_time DATETIME,
end_time DATETIME
);
2️⃣ 订单表 seckill_order
CREATE TABLE seckill_order (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
product_id BIGINT,
create_time DATETIME
);
四、核心流程(答辩必画)
用户请求秒杀
↓
接口限流(Redis)
↓
Redis 预减库存
↓
库存 ≤ 0 → 直接拒绝
↓
MySQL 乐观锁 / 悲观锁扣库存
↓
下单成功
五、四种核心技术方案(⭐重点)
✅ 方案一:悲观锁(MySQL)
SELECT stock FROM seckill_product WHERE id = 1 FOR UPDATE;
@Transactional
public boolean seckill(Long userId, Long productId) {
Product p = productMapper.selectForUpdate(productId);
if (p.getStock() <= 0) return false;
productMapper.decreaseStock(productId);
orderMapper.insert(userId, productId);
return true;
}
📌 缺点:串行化,高并发性能差
✅ 方案二:乐观锁(版本号 / 库存字段)
SQL
UPDATE seckill_product
SET stock = stock - 1,
version = version + 1
WHERE id = #{id}
AND stock > 0
AND version = #{oldVersion};
Java
int rows = productMapper.decreaseStockOptimistic(
productId, oldVersion);
if (rows == 0) {
throw new RuntimeException("并发冲突,秒杀失败");
}
📌 优点:并发性能更好
📌 老师最爱问:ABA 问题(可答:秒杀场景影响不大)
✅ 方案三:Redis 预减库存(⭐核心)
Long stock = redisTemplate.opsForValue()
.decrement("stock:" + productId);
if (stock < 0) {
redisTemplate.opsForValue()
.increment("stock:" + productId);
return "秒杀结束";
}
📌 作用:挡住 90% 无效请求,保护数据库
✅ 方案四:接口限流(Redis + Lua)
Lua 脚本(原子性)
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or '0')
if current + 1 > limit then
return 0
end
redis.call('incr', key)
redis.call('expire', key, 1)
return 1
Java 调用
Long result = redisTemplate.execute(
redisScript,
Collections.singletonList("seckill:limit:" + userId),
"1"
);
if (result == 0) {
return "操作太频繁";
}
📌 作用:防止用户重复刷接口
六、完整秒杀接口(整合版)
@PostMapping("/seckill")
public String seckill(Long userId, Long productId) {
// 1. 限流
if (!rateLimiter.tryAcquire(userId)) {
return "操作频繁";
}
// 2. Redis 预减库存
Long stock = redisTemplate.opsForValue()
.decrement("stock:" + productId);
if (stock < 0) {
return "已售罄";
}
// 3. MySQL 乐观锁扣库存
Product p = productMapper.selectById(productId);
int rows = productMapper.decreaseStockOptimistic(
productId, p.getVersion());
if (rows == 0) {
redisTemplate.opsForValue()
.increment("stock:" + productId);
return "秒杀失败";
}
// 4. 下单
orderMapper.insert(userId, productId);
return "秒杀成功";
}
七、缓存预热(重要)
@PostConstruct
public void initStock() {
Product p = productMapper.selectById(1L);
redisTemplate.opsForValue()
.set("stock:1", p.getStock());
}
八、系统特色(⭐答辩必讲)
✅ Redis 预减库存,数据库保护
✅ 乐观锁 + 悲观锁对比分析
✅ Redis + Lua 原子限流
✅ 可扩展 MQ 异步下单
✅ 高并发场景真实落地
✅ 技术深度明显高于普通 CRUD 项目
九、性能对比(论文 / 答辩加分)
|
方案 |
QPS |
是否超卖 |
|---|---|---|
|
无锁 |
高 |
✅ 超卖 |
|
悲观锁 |
低 |
❌ |
|
乐观锁 |
中 |
❌ |
|
Redis + 乐观锁 |
高 |
❌ |
十、毕设论文结构建议
|
章节 |
内容 |
|---|---|
|
第1章 |
绪论 |
|
第2章 |
相关技术 |
|
第3章 |
需求与场景分析 |
|
第4章 |
系统设计 |
|
第5章 |
核心实现(四种方案对比) |
|
第6章 |
压力测试(JMeter) |
|
第7章 |
总结 |
十一、可扩展方向(工作量拉满)
✅ RabbitMQ 异步下单
✅ 分布式锁(Redisson)
✅ 分库分表
✅ 秒杀页面静态化
✅ 恶意请求风控
✅ 微服务化(Sentinel)
十二、我可以继续帮你做的事 ✅
-
✅ 给你 完整 SpringBoot 秒杀项目
-
✅ 写 第4 / 第5 / 第6 章论文
-
✅ 画 架构图 / 时序图
-
✅ 写 JMeter 压测方案
-
✅ 准备 答辩老师常问问题
-
✅ 改成 分布式 / 微服务版
你现在处于:
👉 开题 / 中期 / 快答辩了 / 面试准备?
告诉我,我按你的目标给你“直接能交的内容”。
更多推荐
所有评论(0)