秒杀超卖问题解剖及解决方案

超卖问题

秒杀往往伴随着高并发,一个处理不好就会出现超卖问题

问题:先校验产品库存,再更新库存

在这里插入图片描述
线程1先校验库存,余100,在线程1未来得及更新库存时,线程2进来校验库存,还是余100,然后两个线程都能更新库存,导致最终结果超卖

解决方案一:乐观锁版本号模式

在更新产品库存时,产品库存等于校验时库存时才更新。
线程1:在校验时库存余100,update t set stock = stock - 60 where id = ? and stock = 100
线程2:在校验时库存余100,update t set stock = stock - 70 where id = ? and stock = 100
线程3:在校验时库存余100,update t set stock = stock - 30 where id = ? and stock = 100

由于在更新库存时有行锁,不同能会同时更新两条,其中一条会阻塞等待另一条更新完,当线程1更新完后库存余40,到线程2再更新时库存已经不是100了,所以线程2会更新失败,这样就可以解决了超卖问题;

再到线程3更新时,线程1更新完库存余40,线程3扣减30,库存充足,理应更新成功,但是由于线程3更新时库存得是100,导致线程3更新失败了;

版本号模式虽然会解决超卖问题,但会导致大量不该失败的请求失败了;

解决方案二:乐观锁,更新后库存大于0

只需要更新后的库存还是大于0就算成功,此时都可以不用先校验库存了
线程1:update t set stock = stock - 60 where id = ? and stock - 60 >= 0
线程2:update t set stock = stock - 70 where id = ? and stock - 70 >= 0
线程3:update t set stock = stock - 30 where id = ? and stock - 30 >= 0

这样不管是线程1先更新,还是线程2先更新,线程3都能够成功更新

问题:为什么不使用悲观锁来解决?

或许会有这种想法:使用悲观锁(java锁),就算先校验库存再更新库存,由于校验库存和更新库存是原子性的,所以也是可以解决的,就算是做集群,也还是可以使用分布式锁来解决;

此时可以换一个思路来想这个问题,无论是用悲观锁,还是乐观锁来处理,最终的结果都是防止库存被扣多了;如果使用悲观锁,如Java锁,或者分布锁,使用锁会降低系统性能和提高代码实现的复杂度,因此没有必要使用悲观锁的方式;

总结

要清楚什么场景下使用乐观锁和悲观锁,一但使用不好,就会增加系统的复杂度;
一般在更新时可以同时做校验的,就可以使用乐观锁;
如果是需要先校验再插入一条新的数据,这时就得考虑悲观锁了;

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值