mysql乐观锁 超卖_秒杀系统之超卖现象

通过本节能学到什么?

什么是抢购的超卖现象?

常见的解决思路有哪些?最好的解决思路是什么?

1、引出问题:

在做抢购系统的时候,我们首先应该想到的是怎么才能避免超卖,比如说:库存只有100,结果卖了200。这种情况肯定是不能接受的。如果我们不在代码中针对该问题进行相应处理,很有可能就会造成这种不良后果。

比如:

MySQL,Redis常见错误处理方式,下面用伪代码来展示下:

# 查询数据库存放的库存

$goods_num = $this->goods_db->get_goods_num($goods_id);

# 判断库存

if($goods_num >=1)

{

# 用户和该订单绑定等处理

# 减库存

}

?>

如上就是我们最常见的处理方式。我们来分析下上面这段代码是怎么造成超卖问题的。当剩余库存为1 ,同时有两名用户请求数据。此时他们同时走到第6行代码,因为此时他们从第3行代码查询到的库存都是1,所以都进入到了if语句里面。都进行了减库存处理,导致库存变成了-1。

2、怎么解决?

首先我们要明确解决该问题的核心原则:于所有的用户对于库存的读写操作必须是串行的!

举例理解:

并行:多位用户同时检查库存,发现有剩余之后同时减库存。如上面的伪代码就是并行。

串行:用户1检查库存--有剩余之后减库存--用户2检查库存--有剩余之后减库存--用户3检查库存--有剩余之后减库存...... 如果回归到上面的伪代码上,就意味着上面的伪代码要执行的话,必须一个人接一个人的执行,不能多人同时执行。

上面已经有了“天上飞的”,下面相应的就要有“地上跑的”

方案:

方案一:Mysql中可以应用悲观锁和乐观锁。

因为该方式不是最好的实现方式,不再展开去讲,可以参考该文章了解下。

方案二(最好):Redis的消息队列。

还是用php代码来处理下:

#########################后台创建商品侧################################################

# 在创建商品库存的时候,同时创建一个该商品的redis list key ,来存放该商品所有的库存。

$goods_num = 100;

$goods_id = 1;

$goods_list_key = 'goods_num:'.$goods_id;

for($i=0; $i

{

$Redis->Lpush($goods_list_key,1);

}

# 经过上面一番操作,$goods_list_key已经存放了100个元素,每个元素都是1

#########################################################################

......

#########################前台用户抢购商品侧###############################################

$goods_id = 1;

$goods_list_key = 'goods_num:'.$goods_id;

$user_get_goods = $Redis->Lpop($goods_list_key);

if(!empty($user_get_goods)))

{

# 用户和商品建立绑定关系

# 减库存(到MySQL或者Redis减库存都行,不过一般这种落地数据都会采用放到MySQL中)

}

#########################################################################

?>

下面来分析下,上面这段代码是如何避免掉超卖问题的。

当商品的库存只剩下1的时候,此时有两位用户同时来取商品。第一个用户把库存取走(pop)之后;第二个用户再来取库存(pop)的时候,发现什么也没取到,那么就直接返回就行,也不需要再去减库存。

拓展:

注意实际项目中一般稍微复杂一点,还有加一条逻辑:一位用户只能取一个商品,多次来的请求并不能多次取商品。这条也非常常见的要求,毕竟万一有用户来刷,没有限制的话,所有商品可能都被该用户取走。

思路:只需要在进行领取之前查询下用户是否已经领取过即可

实际场景:

最近做了一个需求,虽然不是抢购,但是也是有库存限制。由于没有针对超卖问题进行处理,就出现了库存为-1的情况。如上面优化之后就没有问题了。

参考文档:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值