讲师中心 微信公众号
AI工具推荐 视频效率加速

在MySQL高并发扣减库存时如何设计行锁机制防止超卖

风强姑娘_3439

风强姑娘_3439

发布时间:2026-09-04 11:53:25

|

821人浏览过

|

来源于php中文网

原创

SELECT ... FOR UPDATE 必须在显式事务中使用,否则锁立即释放;可靠防超卖应采用原子UPDATE语句(如UPDATE ... WHERE id=? AND stock>=1),配合唯一索引防重、乐观锁适配读多写少场景,并确保WHERE条件走索引避免表锁。

在mysql高并发扣减库存时如何设计行锁机制防止超卖

SELECT ... FOR UPDATE 必须在显式事务里用

单独执行 SELECT ... FOR UPDATE 没用,InnoDB 只在事务中才真正加锁。如果 autocommit=1(默认),那这条语句一执行完就自动提交、锁立刻释放,后续的 UPDATE 完全不受保护。

必须显式开启事务:

START TRANSACTION;
SELECT stock FROM goods WHERE id = 123 FOR UPDATE;
-- 应用层判断 stock > 0
UPDATE goods SET stock = stock - 1 WHERE id = 123;
COMMIT;

常见错误现象:日志里看到“查到 stock=1”,但最终库存变成 -2;本质是查完就释放锁,多个事务都读到了旧值。

  • 连接池配置要关掉自动提交(autocommit=false)
  • FOR UPDATE 只对 InnoDB 有效,MyISAM 不支持
  • 若 WHERE 条件不走索引,会升级为表锁,直接拖垮并发能力

UPDATE 带条件才是防超卖的兜底写法

依赖 SELECT ... FOR UPDATE + 应用层判断,逻辑链太长,中间任意环节出错(比如网络延迟、服务重启、代码分支遗漏)都会漏掉检查。真正可靠的是把“判断”和“更新”压进一条 SQL:

UPDATE goods SET stock = stock - 1 WHERE id = 123 AND stock >= 1;

执行后看 ROW_COUNT():

  • 返回 1 → 扣减成功
  • 返回 0 → 库存不足或记录不存在,没做任何修改

这条语句天然具备三重保障:InnoDB 自动对匹配行加 X 锁、WHERE 和 SET 原子执行、不依赖应用层读取值。即使 5000 个请求并发打进来,也只有一个能拿到锁并满足条件,其余全部静默失败。

注意:AND stock >= 1 不能写成 AND stock > 0 —— 虽然语义等价,但部分 MySQL 版本对 > 0 的索引优化略差,>= 1 更稳妥。

唯一索引 + INSERT 先判重,比锁更轻量

防重复下单和防超卖可以拆开处理。比如用户秒杀资格,用 (uid, goods_id) 唯一索引比加锁查 buy_record 表快得多:

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载
INSERT INTO buy_record (uid, goods_id) VALUES (1001, 2001);

如果报错 Duplicate entry '1001-2001' for key 'uk_uid_goods',说明已参与过,直接拒绝。

接着再扣库存:

UPDATE goods SET stock = stock - 1 WHERE id = 2001 AND stock >= 1;

这种组合把“查是否买过”从锁操作降级为索引冲突检测,避免了大量 SELECT ... FOR UPDATE 堵塞。适用于秒杀类场景,且要求业务能接受“先抢资格、再扣库存”的两段式语义。

  • 唯一索引必须是 UNIQUE 类型,普通 INDEX 不拦截重复插入
  • MySQL 返回的错误码是 1062,应用层要捕获这个特定错误,而不是泛化地 catch SQLException

乐观锁 version 字段适合读多写少场景

如果库存变更不频繁(比如后台运营调价、补货),但查询极多(商品详情页 PV 高),用 version 字段比行锁更省资源:

UPDATE goods SET stock = stock - 1, version = version + 1 WHERE id = 123 AND version = 10;

返回影响行数为 0,说明在你查完 version 后,别人已经改过数据,此时应重试或提示“库存变化,请刷新”。

但它不适合秒杀:1000 人同时查到 version=10,然后一起发 UPDATE,999 个会失败,重试风暴可能压垮数据库。

  • version 字段类型推荐 INT UNSIGNED 或 BIGINT,避免溢出
  • 不能只靠 version 判断库存是否足够,仍需 stock >= 1 条件,否则 version 对得上但库存已为 0,也会扣成负数

最易被忽略的一点:所有这些方案都假设 goods.id 是主键或有唯一索引。如果 WHERE 条件走不了索引,InnoDB 会锁整张表——高并发下等于直接拒绝服务。

热门AI工具

更多
火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

DeepSeek

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

WorkBuddy

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

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

豆包大模型

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

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

相关专题

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

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

4443

2023.10.12

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

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

931

2023.10.27

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

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

1169

2024.02.23

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

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

6381

2024.03.06

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

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

3183

2024.03.06

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

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

6360

2024.04.07

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

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

8661

2024.04.29

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

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

1170

2024.04.29

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

0

2026.10.22

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 189人学习

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

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