秒杀并发过程动画

左侧演示 unsafe 的“先查后改”如何超卖;右侧演示 atomic 的数据库条件扣减如何把成功订单限制在库存以内。

请求进入 读取库存 成功下单 超卖订单 售罄失败

Unsafe 的问题点

“判断库存”和“扣库存”分成两步,中间存在竞态窗口。并发请求会同时看到库存还够,于是都继续创建订单。

Atomic 的关键点

把“库存必须大于 0”和“库存减 1”放进同一条数据库更新语句,数据库只会让有限库存对应的请求成功。

Unsafe:先查库存,再扣库存

多个请求同时读到同一个旧库存,各自认为可以下单,最后写回时互相覆盖。

等待播放
当前阶段:等待播放 点击播放后,请关注多个请求是否读到了同一个旧库存。

实现路径

select stock if stock > 0: sleep(放大竞态窗口) update stock = oldStock - 1 insert order
库存5
订单0
超卖0
并发窗口:请求重叠执行
用户请求
业务服务
数据库
ServiceselectById
sleep
updateById
DBstock=5
orders=0
无原子条件
读旧库存后继续写入
写入订单0 条
本应拒绝0 条超卖仍写入
多个请求读到 stock=5

Atomic:一条 SQL 条件扣减

扣库存和判断库存合并到数据库原子更新里,库存为 0 后直接失败。

等待播放
当前阶段:等待播放 点击播放后,请关注每个请求是否都必须通过数据库条件扣减。

实现路径

UPDATE seckill_product SET stock = stock - 1 WHERE id = ? AND stock > 0 affectedRows == 1 才 insert order
库存5
订单0
失败0
并发请求:由数据库排队判定
用户请求
业务服务
数据库
ServicedeductStockIfAvailable
DBstock=5
orders=0
SQL gate
stock > 0 ? affectedRows
写入订单0 条
被 SQL 拒绝0 条 affectedRows=0