You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

高流量应用多连接下MySQL UPDATE并发异常的解决方法

解决MySQL高并发下UPDATE的库存超卖问题

你遇到的是典型的并发更新导致的库存超卖问题——两个请求同时读取到相同的库存值(5),各自执行减5操作后最终导致负数。以下是几种可靠的解决方案:

1. 在UPDATE语句中直接加入库存校验条件

最直接高效的方式是把库存充足的判断写进UPDATE的WHERE子句,让数据库层面保证只有库存足够时才执行更新:

UPDATE table SET balls=balls-5 WHERE marketId=3212 AND balls >=5;

执行后务必检查受影响的行数:

  • 受影响行数为1:更新成功,库存正常扣减;
  • 受影响行数为0:库存不足,直接返回用户“库存不足”提示即可。

这种方式利用MySQL的原子性保证操作一致性,无需额外事务或锁,性能最优。

2. 事务结合行级锁(悲观锁)

如果业务需要先读取库存做额外判断(比如用户权限校验),再执行更新,可以用事务+行级锁避免并发冲突:

START TRANSACTION;
-- 锁定指定行,其他请求需等待当前事务提交后才能操作该行
SELECT balls FROM table WHERE marketId=3212 FOR UPDATE;
-- 此处可加入业务逻辑判断(如用户是否有购买资格)
-- 确认库存足够后执行更新
UPDATE table SET balls=balls-5 WHERE marketId=3212 AND balls >=5;
COMMIT;

注意事项:

  • 确保表使用InnoDB引擎(MyISAM不支持行锁);
  • 事务要尽可能短,避免长时间占用锁导致其他请求超时;
  • 依赖InnoDB默认隔离级别(REPEATABLE READ)即可,无需额外调整。

3. 乐观锁(版本号机制)

针对极高并发场景,乐观锁是更高效的选择——它不会主动锁定行,而是通过版本号检测并发冲突:

  1. 给表新增version字段(INT类型,默认值0);
  2. 读取库存时同时获取当前版本号:
    SELECT balls, version FROM table WHERE marketId=3212;
    
  3. 更新时带上版本号条件,仅当版本号匹配时执行更新:
    UPDATE table SET balls=balls-5, version=version+1 WHERE marketId=3212 AND balls >=5 AND version=读取到的版本号;
    
  4. 检查受影响行数:
    • 受影响行数为1:更新成功;
    • 受影响行数为0:说明有其他请求已修改该行,可重试(最多几次)或提示用户“操作失败,请重试”。

这种方式无锁等待,性能损耗低,但需要处理重试逻辑。


内容的提问来源于stack exchange,提问作者Stuart William

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 09:35:01