mysql并发扣减库存如何实现_mysql原子操作设计
发布时间 - 2026-01-04 00:00:00 点击率:次正确做法是UPDATE时在WHERE中加入库存校验条件,如WHERE id = 123 AND stock >= 1,并检查ROW_COUNT();复杂逻辑需配合SELECT FOR UPDATE加行锁,且WHERE条件避免函数导致索引失效。
UPDATE WHERE 语句必须带库存校验
并发扣减库存最直接的错误,就是只写 UPDATE product SET stock = stock - 1 WHERE id = 123。这会导致超卖:两个请求同时读到 stock=1,各自执行减 1,最终变成 -1。
正确做法是把库存是否充足判断直接塞进 WHERE 条件里,让 MySQL 在更新前原子性校验:
UPDATE product SET stock = stock - 1 WHERE id = 123 AND stock >= 1;
执行后检查 ROW_COUNT()(MySQL 返回影响行数):
- 返回 1 → 扣减成功
- 返回 0 → 库存不足或记录不存在,需业务层拒绝下单
务必使用 SELECT FOR UPDATE 配合事务
当扣减逻辑不止一行 SQL(比如要先查价格、再扣库存、再写订单),单纯靠 WHERE 校验不够,必须加行锁防止并发读写冲突。
关键点:
- 必须在
START TRANSACTION内执行 -
SELECT ... FOR UPDATE会锁定该行(即使没命中索引,可能升级为表锁) - 锁持续到事务结束(
COMMIT或ROLLBACK),不是语句结束
示例:
START TRANSACTION; SELECT stock FROM product WHERE id = 123 FOR UPDATE; -- 此时其他事务对 id=123 的 SELECT FOR UPDATE / UPDATE 会被阻塞 UPDATE product SET stock = stock - 1 WHERE id = 123 AND stock >= 1; -- 检查 ROW_COUNT(),失败则 ROLLBACK COMMIT;
避免 WHERE 条件中使用函数或表达式导致索引失效
如果写成 WHERE id = ? AND stock - 1 >= 0,MySQL 无法用上 stock 索引(哪怕有联合索引),可能触发全表扫描+锁表,极大降低并发能力。
应始终保持 WHERE 中的列是独立出现的:
- ✅
WHERE id = 123 AND stock >= 1(能走PRIMARY KEY+ 范围条件) - ❌
WHERE id = 123 AND stock - 1 >= 0(stock - 1是表达式,索引失效) - ❌
WHERE id = 123 AND stock > 0(虽然语义等价,但某些旧版本优化器可能不走索引,>= 1更稳)
高并发场景下慎用自增 ID 做库存分片依据
有人想用 id % 4 把商品分散到不同行来缓解热点,但这会破坏业务语义(同一商品多行库存难聚合),且无法解决单商品高并发问题。
真正有效的分片思路是:
- 按业务维度拆分:比如「SKU + 仓库编码」作为联合主键,不同仓库存独立扣减
- 用 Redis 预减库存(异步落库),但需处理 Redis 故障/回滚一致性问题
- 数据库端改用乐观锁(version 字段)+ 重试,适合冲突率低的场景
纯 MySQL 方案里,UPDATE ... WHERE ... AND stock >= N + 事务 + 索引覆盖,已经能扛住几千 QPS 的秒杀流量;再往上,就得考虑缓存、队列、分库分表了。
# mysql
# redis
# 编码
# 热点
# red
# sql
# for
# select
# 并发
# 异步
# 数据库
# 这会
# 分片
# 不存在
# 就得
# 要先
# 不走
# 想用
# 升级为
# 读到
# 塞进
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?
Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】
专业商城网站制作公司有哪些,pi商城官网是哪个?
如何在IIS管理器中快速创建并配置网站?
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
如何用AI帮你把自己的生活经历写成一个有趣的故事?
标题:Vue + Vuex + JWT 身份认证的正确实践与常见误区解析
Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧
如何批量查询域名的建站时间记录?
哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
如何在香港免费服务器上快速搭建网站?
如何快速使用云服务器搭建个人网站?
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
Laravel如何使用Livewire构建动态组件?(入门代码)
Laravel storage目录权限问题_Laravel文件写入权限设置
Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程
android nfc常用标签读取总结
Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践
Laravel如何实现多对多模型关联?(Eloquent教程)
如何快速生成ASP一键建站模板并优化安全性?
JS弹性运动实现方法分析
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
Laravel全局作用域是什么_Laravel Eloquent Global Scopes应用指南
百度输入法ai组件怎么删除 百度输入法ai组件移除工具
,网页ppt怎么弄成自己的ppt?
Angular 表单中正确绑定输入值以确保提交与验证正常工作
动图在线制作网站有哪些,滑动动图图集怎么做?
如何快速启动建站代理加盟业务?
网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践
zabbix利用python脚本发送报警邮件的方法
如何快速查询网址的建站时间与历史轨迹?
javascript中的数组方法有哪些_如何利用数组方法简化数据处理
如何选择PHP开源工具快速搭建网站?
谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程
深入理解Android中的xmlns:tools属性
,怎么在广州志愿者网站注册?
购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?
Laravel如何实现API速率限制?(Rate Limiting教程)
Laravel Eloquent:优雅地将关联模型字段扁平化到主模型中
如何在服务器上三步完成建站并提升流量?
Laravel如何构建RESTful API_Laravel标准化API接口开发指南
Linux系统命令中tree命令详解
Bootstrap CSS布局之列表
夸克浏览器网页跳转延迟怎么办 夸克浏览器跳转优化
如何用西部建站助手快速创建专业网站?
Laravel怎么使用Intervention Image库处理图片上传和缩放
高配服务器限时抢购:企业级配置与回收服务一站式优惠方案


确做法是UPDATE时在WHERE中加入库存校验条件,如WHERE id = 123 AND stock >= 1,并检查ROW_COUNT();复杂逻辑需配合SELECT FOR UPDATE加行锁,且WHERE条件避免函数导致索引失效。