讲师中心 微信公众号

工具推荐

视频效率加速
Seko
Seko

AI短剧一键生成成片

Laper
Laper

剧本策划到成片协作

AniShort
AniShort

AI短剧协同制作平台

updream

一键生成高质量推广成片

怎样在MySQL5.7中实现高并发秒杀扣减零死锁

夜萱姑娘_9868

夜萱姑娘_9868

发布时间:2026-11-15 10:15:48

|

875人浏览过

|

来源于php中文网

原创

直接UPDATE扣减必致高并发锁争抢,因所有请求挤在同一行物理位置强制串行化;应改用INSERT ON DUPLICATE KEY UPDATE分片扣减,避免临键锁且锁粒度限于单shard。

怎样在mysql5.7中实现高并发秒杀扣减零死锁

为什么直接 UPDATE ... SET stock = stock - 1 WHERE id = ? 在秒杀中必死锁

不是语句本身错,而是它在高并发下触发了死锁的全部四个条件:互斥(X锁)、持有并等待(事务里还有其他操作)、不可剥夺(InnoDB不支持强制释放行锁)、循环等待(多个事务随机竞争同一行)。MySQL 5.7 默认 REPEATABLE READ 隔离级别,WHERE id = ? 走主键索引时加的是临键锁(Next-Key Lock),但若事务中混入范围查询或间隙操作,锁范围会意外扩大;更致命的是——所有请求都挤在同一个 id 上,物理位置固定、锁争抢串行化,等于把并发压成单线程。

必须绕开行锁竞争:用 INSERT ... ON DUPLICATE KEY UPDATE 替代 UPDATE

核心思路是把“更新一行”变成“尝试插入一条唯一记录”,靠唯一约束触发原子性判断,避免显式加 X 锁。适用于已预分片的库存表:

CREATE TABLE `goods_stock_shard` (
  `goods_id` INT NOT NULL,
  `shard_id` TINYINT NOT NULL,
  `stock` INT NOT NULL DEFAULT 0,
  PRIMARY KEY (`goods_id`, `shard_id`)
) ENGINE=InnoDB;

扣减时随机选一个 shard_id(如 shard_id = FLOOR(RAND() * 10)),执行:

INSERT INTO goods_stock_shard (goods_id, shard_id, stock)
VALUES (123, 7, -1)
ON DUPLICATE KEY UPDATE stock = stock - 1;

注意三点:

win可用的mysql指令skill
win可用的mysql指令skill

安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。

下载
  • INSERT 不会加临键锁,只在插入冲突时对已有记录加 X 锁,且锁粒度仅限该 (goods_id, shard_id) 组合
  • 必须确保 stock 初始值 ≥ 0,否则 stock - 1 可能为负——业务层需用 SELECT stock FROM ... WHERE goods_id = ? AND shard_id = ? 做兜底校验
  • 不能依赖 ROW_COUNT() 判断是否扣减成功:冲突时返回 2(insert + update),无冲突时返回 1(纯 insert),需结合 SELECT 确认最终值

为什么不能只靠 SELECT ... FOR UPDATE 加锁顺序统一

统一加锁顺序(比如总先查 users 再查 orders)对多表事务有效,但秒杀本质是单表单行热点,所有事务天然锁同一行——顺序再统一也没用。更危险的是:SELECT ... FOR UPDATE 在 REPEATABLE READ 下会加 Next-Key Lock,若索引扫描范围稍大(比如用了非唯一二级索引),就会带上 Gap Lock,两个事务分别锁定 (100, 200) 和 (200, 300) 区间,再插入 200 就可能互相等待。

真实踩坑点:

  • 开发曾用 SELECT stock FROM goods WHERE id = 123 FOR UPDATE 后判断再 UPDATE,结果因网络延迟导致锁持有超 2 秒,QPS 一过 300 就开始报 Deadlock found when trying to get lock
  • ORM 框架(如 MyBatis)自动生成的 SQL 可能隐式带 ORDER BY 或 LIMIT,改变执行计划,使本该走主键的查询走了全表扫描,锁升级为表级
  • innodb_lock_wait_timeout 默认 50 秒,但秒杀场景要求失败响应

真正零死锁的关键:彻底剥离数据库的“判断-执行”耦合

MySQL 5.7 的 InnoDB 不可能在单行高并发写上做到绝对零死锁,所谓“零死锁”是指:死锁发生率趋近于 0,且一旦发生不影响业务正确性。这只能靠架构解耦实现:

  • 前置用 Redis DECRBY 做库存快照:初始化时 SET goods:123:stock 1000,扣减前 DECRBY goods:123:stock 1,返回值
  • Redis 扣减成功后,异步发消息到 Kafka,由消费者按固定速率(如 300 QPS)批量写入 MySQL 分片表,此时数据库压力已降两个数量级
  • MySQL 层只承担最终一致性落库,不再参与实时决策;即使某次消费失败,靠消息重试+幂等 INSERT ... ON DUPLICATE KEY UPDATE 保证不超卖

最容易被忽略的一点:分片后仍要避免 shard_id 被人为固定(比如永远用 0),否则又回到单行热点。必须用服务端真随机(非客户端 RAND()),且分片数建议 ≥ 16,让锁竞争分散到不同页(Page)上。

热门AI工具

更多
小橡皮AI

一款AI工具,主要用于小橡皮一键去AI味,将机器味重的内容改得更有活人感,防止因为 AI 内容被平台打上 AI 标签,以及限流,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

5003

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1011

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

1309

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

7081

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

3723

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

7060

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

9881

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

1350

2024.04.29

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

40

2026.11.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn