有懂秒杀的兄弟吗?为什么 mysql 这样会出现超卖的问题

2018-11-20 17:15:26 +08:00
 cyhulk
首先设定一个前提,为了防止超卖现象,所有减库存操作都需要进行一次减后检查,保证减完不能等于负数。(由于 MySQL 事务的特性,这种方法只能降低超卖的数量,但是不可能完全避免超卖)

update number set x=x-1 where (x -1 ) >= 0;
为什么这条语句会出现超卖
16462 次点击
所在节点    Java
84 条回复
cyhulk
2018-11-21 10:40:35 +08:00
@karllynn 这个没事的,可能是为了逻辑清晰,而且数据库的优化器会帮你查处理成 x > 0 的
realpg
2018-11-21 10:48:30 +08:00
事务呢……
mineqiqi
2018-11-21 11:43:55 +08:00
上 redis 分布式锁是比较好的解决方案
saltxy
2018-11-21 11:59:04 +08:00
网上的博客都是到处抄,连写错的地方都是一模一样~这条语句顶多就是高并发扛不住,库存是不会减到负数的
jzmws
2018-11-21 13:12:36 +08:00
数据库把 库存的数量设置为 unsigned 的类型 数据库做个最后的拦截
Exceptions
2018-11-21 13:13:43 +08:00
这个和事务没关系,update 不管在 innodb 下是行锁还在 myisam 下是表锁, 都不会造成负数的情况。网上博客一大抄,看看就行了,别较真, 真较真起来能气死自己....
HamQ
2018-11-21 13:56:54 +08:00
@xavier007 小米不是到预售时间直接改文字变售罄嘛 不需要秒杀这么高级的玩意的
mnhkahn
2018-11-21 14:06:58 +08:00
你们秒杀没量吗?居然数据库减
micean
2018-11-21 14:10:22 +08:00
贴一下超卖的博客看一下?
lixikei
2018-11-21 14:40:45 +08:00
秒杀这种场景,直接减数据库,总会有意想不到的惊喜。
lixikei
2018-11-21 14:42:32 +08:00
秒杀开始前,先将库存信息存到 redis、memcache 里,减库存直接内存减,订单付款结束更新数据库。
xiaoxiaoan317
2018-11-21 14:50:28 +08:00
高并发,首先要做上游拦截,然后使用内存队列,最后异步处理,mysql 就可以轻轻松松应对了
qilishasha
2018-11-21 15:04:33 +08:00
设计模式可以看一下……不要相信那些博客上愚蠢的办法(我朝当真是人才济济)…… 12306 坑那么久也是没得说了,可以多看看 12306 的解决方案,不要浪费时间在数据库这种东西的操作上,不要感谢我,我的名字叫雷锋!
weizhen199
2018-11-21 15:07:31 +08:00
大哥啊,用队列啊,数据库🔒吃不消啊
cyhulk
2018-11-21 16:43:54 +08:00
@Exceptions 是行锁没问题,但是不同隔离级别的下的锁类型可能也不一样,X 锁还是 S 锁,这个我也不是特别清楚,其实一直想找个 DBA 问下
Exceptions
2018-11-21 17:07:57 +08:00
@cyhulk 底层用到的锁肯定不止这两种,排它锁共享锁间隙锁范围锁意向锁等等,事务下每次更新数据,都会用到特定的锁去锁定,然后修改数据存到 redo 日志,旧数据存到回滚段的 undo 日志里,读取都是不加锁的快照读,直接读取 undo 日志的数据,所以 innodb 才适合高并发的互联网应用
cyhulk
2018-11-21 17:29:26 +08:00
@Exceptions 不考虑 RC 和 RR 级别,这两个都是严格的 X 锁,RR 还要加间隙锁,我唯一不确定的就是 Read uncommit 级别下的是否是 S 锁,如果是 S 锁,确实可能会存在,但是我实践上没有这个问题
wentaoliang
2018-11-21 17:53:34 +08:00
为啥上面一堆人在扯事务的隔离级别, 这个事务隔离级别有毛的关系,我觉得这和 update number set x=x-1 where x >= 1 没区别, 会把 x >= 1 的全部加上行锁,所以不会超发
he583899772
2018-11-21 17:54:56 +08:00
我以前也出现超卖了,后来我用 redis 链表实现的,活动前吧库存缓存到 redis 列表,放在下订单逻辑的前面,卖一个出一个,为空就报错了,不让创建订单,前端也搞搞几层缓解一下并发
cyhulk
2018-11-21 17:58:13 +08:00
@he583899772 为啥要用列表呢?直接数字 incrby 不也可以吗?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/509707

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX