点击上方SQL数据库开发,关注获取SQL视频教程
SQL专栏
本文作者:璀璨小二
原文:https://www.cnblogs.com/clphp/
1. 问题的来源
一定要高性能,不然还能叫秒杀吗?
要强一致性,库存只有100个,不能卖出去101个吧?但是库存10000实际只卖了9999是否允许呢?
既然这里说了是秒杀,那往往还会针对每个用户有购买数量的限制。
下文的所有解决方案是在 Mysql InnoDB 下做的。因为用到了很多数据库特性。其他的数据库或其他的数据库引擎会有不同的表现,请注意。
2.完全不考虑一致性的方案
2.1 表结构
2.2 方案
user和
deal的关联表。谁买了多少就插入数据呗。
buy_count是否超过单人购买限制。
select sum(buy_count) from UserDeal where deal_id = ?select count(*) from UserDeal where user_id = ? and deal_id = ?insert into UserDeal (user_id, deal_id, buy_count) values (?, ?, ?)2.3存在的问题
如果库存只剩一个,两个用户同时点购买,两个人检查全部成功,最后,就超卖了。
如果一个用户同时发起两次请求,检测部分同样可能会同时通过,最后,数据就异常了。
3.保证单用户不会重复购买
alter table UserDeal add unique user_id_deal_id(user_id, deal_id)4. 解决超卖问题
4.1 方案
select语句没有使用
for update关键字,所以就算加入了事务也不会影响其他人读写。
select语句即可:
select sum(buy_count) from UserDeal where deal_id = ? for update4.2 优化
deal也会相互影响呢?
select语句中的查询条件是
where deal_id = ?,你以为只会锁所有满足条件的数据对吧?
alter table UserDeal add index ix_deal_id(deal_id)05. 提高性能了
06. 鱼与熊掌不可兼得
6.1 优化的思路
6.2 秒杀可以容忍什么
7. 为了性能牺牲一致性的设计方案
7.1 去掉了事务会发生什么
for update锁行就无效了,我们可以另辟蹊径,来解决这个问题。
7.2 修改表结构
Deal表,其实它就是存了一下基本信息,包括最大售卖量。
sum(buy_count)操作来得到已经卖掉的数量的,然后进行判断后再进行插入数据。
Deal表,把已经售卖的量也存放在
Deal表中,然后巧妙地把操作转换成一行
update语句。
7.3 修改执行过程
update语句来了:
update Deal set buy_count = buy_count + 1 where id = ? and buy_count + 1 <= buy_maxbuy_max是1000,如果有2000个用户同时操作会发生什么?
update语句天然会有行锁,前1000个用户都会执行成功,返回生效行数1。而剩下的1000人不会报错,但是生效行数为0。
update语句的生效行数就知道是否抢购成功了。
7.4 还没有结束
update的生效行数是1,就代表购买成功。所以,如果一个用户购买成功了,那么就再去
UserDeal表中插入一下数据。
Deal表把刚才购买的还回去:
update Deal set buy_count = buy_count - 1 where id = ? and buy_count - 1 >= 0buy_count - 1 < 0的情况,除非你实现的不对。


执行成功
无库存
回滚成功
损失库存
8. 不要过度优化
——End——
后台回复关键字:1024,获取一份精心整理的技术干货 后台回复关键字:进群,带你进入高手如云的交流群。 推荐阅读
点击「阅读原文」了解SQL训练营
最后修改时间:2020-04-27 08:10:14
文章转载自SQL数据库开发,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。






