新闻详情

新闻详情

首页 / 资讯中心 / 详情

MySQL 明明只更新一行,为什么一直卡住?用两个会话理解行锁与库存扣减

发布时间:2026/10/2 8:30:35来源:尧图网络
MySQL 明明只更新一行,为什么一直卡住?用两个会话理解行锁与库存扣减
下面这条 SQL 使用主键定位看起来应该很快UPDATE inventory SET stock stock - 1 WHERE sku_id 1001;但在并发环境下它仍可能等待数秒甚至超时。原因不一定是没有索引也可能是另一笔事务持有锁迟迟没有结束。本文通过两个数据库会话解释普通查询为什么可能不等待。更新为什么需要等待。怎样避免库存超卖。锁等待与死锁有什么区别。示例面向MySQL 8.4、InnoDB、REPEATABLE READ。以下为复现步骤与预期现象未将其冒充实测截图。一、准备实验数据在测试数据库执行CREATE TABLE inventory ( sku_id BIGINT PRIMARY KEY, stock INT NOT NULL, CHECK (stock 0) ) ENGINE InnoDB; INSERT INTO inventory (sku_id, stock) VALUES (1001, 10), (1002, 10);然后打开两个独立连接分别称为会话 A 和会话 B。在两个会话中分别执行SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;二、实验一更新一行为什么会等待会话 ASTART TRANSACTION; UPDATE inventory SET stock stock - 1 WHERE sku_id 1001; -- 暂时不要提交。此时A 已经修改了记录但事务尚未结束。会话 BSTART TRANSACTION; UPDATE inventory SET stock stock - 1 WHERE sku_id 1001;预期B 的更新进入等待。因为 A 持有该记录的排他锁而 B 也需要修改同一条记录。现在回到 ACOMMIT;B 随后可以继续执行。最后在 B 中提交COMMIT;查询SELECT * FROM inventory WHERE sku_id 1001;预期库存为8。主键索引可以缩小定位和加锁范围但不能消除同一条记录上的写冲突。三、普通 SELECT 为什么可能不等待为了观察这个差异可以重新设置库存UPDATE inventory SET stock 10 WHERE sku_id 1001;A 再次执行START TRANSACTION; UPDATE inventory SET stock 9 WHERE sku_id 1001;A 不提交。B 在一个新的事务中执行START TRANSACTION; SELECT stock FROM inventory WHERE sku_id 1001;在该实验条件下普通一致性读可以通过 MVCC 读取可见的已提交版本通常会得到10而不等待 A 释放记录锁。但换成SELECT stock FROM inventory WHERE sku_id 1001 FOR UPDATE;就需要获取锁可能等待 A。普通一致性读与锁定读解决的是不同问题。MySQL 官方也指出读取后需要修改相关数据时普通SELECT不足以提供所需保护。MySQL 锁定读文档实验结束后让 A、B 分别提交或回滚避免把事务留在后台。四、为什么“先查库存再更新”容易出错考虑下面的应用逻辑查询库存 如果库存大于 0 扣减库存 创建订单假设只剩一件商品两个请求可能同时读到stock 1然后都判断库存充足。如果后续更新没有重新检查库存条件可能发生负库存如果两个请求都把库存写成0也可能出现库存没有负数却生成两笔有效订单的情况。因此检查与修改不能只依赖应用层先前读到的值。五、用条件 UPDATE 合并判断与扣减对于单个 SKU 的简单扣减可以使用UPDATE inventory SET stock stock - 1 WHERE sku_id 1001 AND stock 1;应用立即读取更新结果影响 1 行本次扣减成功。影响 0 行记录不存在或者库存不足。可以做一个并发实验先将库存设置为1再让两个会话执行这条 SQL。先获得锁的事务扣减成功。它提交后另一个更新会基于可更新记录重新判断条件因此不能再次扣减。这与“先普通查询一次再根据旧结果无条件更新”不同。实际购买数量也必须验证为正数UPDATE inventory SET stock stock - :quantity WHERE sku_id :sku_id AND stock :quantity;如果允许负数数量进入这条 SQL就可能反而增加库存。六、扣库存成功订单创建失败怎么办如果库存与订单在同一个数据库事务中可以这样组织BEGIN 条件扣减库存 检查影响行数 创建订单 COMMIT任何一步失败都回滚整个业务事务。但如果订单创建通过远程服务完成本地事务就不能自动保证远端操作的一致性需要另行设计跨服务流程。还有一个独立问题同一个请求重试两次条件扣减可能成功两次。因此防超卖与请求幂等不是同一件事。后者通常需要稳定的业务请求标识和唯一约束。七、锁等待和死锁有什么区别前面的实验是B 等 A只要 A 结束B 就可以继续。死锁则可能是A 持有商品 1001等待商品 1002 B 持有商品 1002等待商品 1001可以按顺序复现步骤会话 A会话 B1开启事务更新 10012开启事务更新 10023更新 1002进入等待4更新 1001形成循环等待启用死锁检测时InnoDB 会选择一个事务回滚解除循环。应用不能假设永远回滚某一方。可以检查SHOW ENGINE INNODB STATUS;其中包含最近一次死锁的信息。官方建议缩短事务、统一访问顺序并准备重试被回滚的事务。MySQL 死锁处理文档例如多 SKU 扣减时统一按 SKU ID 排序可以减少不同加锁顺序引发的死锁但不能保证所有死锁都消失。八、实际排查应该看什么当主键更新仍然很慢时可以优先检查SELECT * FROM sys.innodb_lock_waits;该视图需要相应环境和访问权限。重点不是只盯住正在等待的 SQL而是找出谁持有锁。持锁事务运行了多久。是否在事务中等待远程接口。是否存在忘记提交的连接。加快 SQL 本身与缩短事务持锁时间是两条不同的优化路径。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

开源三天 9900 star!把 CodeX 塞进 Claude Code 后,TaoToken 统一 Key 怎么配? 2026/10/2 10:59:44

开源三天 9900 star!把 CodeX 塞进 Claude Code 后,TaoToken 统一 Key 怎么配?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Kimi Claw 实战:在 Kimi 里用 OpenClaw 的完整指南与 TaoToken 配置 2026/10/2 10:59:43

Kimi Claw 实战:在 Kimi 里用 OpenClaw 的完整指南与 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
阿里云通义全尺寸开源下载破2000万:用TaoToken统一Key跑通百炼模型调用 2026/10/2 10:59:37

阿里云通义全尺寸开源下载破2000万:用TaoToken统一Key跑通百炼模型调用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
ETL流程设计实战:DFD建模与异构同构选型指南 2026/10/2 10:59:37

ETL流程设计实战:DFD建模与异构同构选型指南

简介:本资源是一份面向数据仓库工程师、ETL开发人员及求职面试者的专业PPT课件,系统梳理ETL核心流程、数据流建模方法与工程化解决方案。内容覆盖ETL定义与目标、实施前提(范围界定与工具选型)、四大执行原则(中转区预…

阅读更多 →
2026年AI工业控制系统搭建指南:从数据到部署的四层架构 2026/10/2 10:59:37

2026年AI工业控制系统搭建指南:从数据到部署的四层架构

2026年搭AI工业控制系统,别急着买AI盒子,先把这四层想清楚这两年问我最多的问题就是“2026年AI工业控制系统到底怎么搭”。问的人多了,我反倒越来越谨慎——因为很多朋友一开口就是“上个AI大模型、买两台AI工控机”,仿佛工业AI是…

阅读更多 →
可迁移的记忆层:让Agent换框架不失忆的设计与实践 2026/10/2 10:59:37

可迁移的记忆层:让Agent换框架不失忆的设计与实践

写个 Agent 记忆系统,最烦的就是“换框架等于失忆”。今天聊的这件事,就是我把 Agent 的长期记忆从特定工具里彻底拆了出来,做成一个独立、可迁移、跨框架的记忆层。折腾完以后,不管底层用的是 LangChain、Spring AI 还是手搓的循…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉