问题
一个很常见的商品秒杀场景,为了防止商品超卖使用了 redis 原子自减方式做库存判断
流程类似这样
下单 => 扣redis库存成功 => 创建订单 => 支付成功, 更新数据库
关键代码如下
$num = 10;
if( $redis->decrBy('goods_id', $num) > 0) { // 库存足够
// create_order 创建订单成功返回 true, 失败返回 false
if( !create_order() ) {
// 创建订单失败,回退库存
$redis->incrBy('goods_id', num);
}
} else { // 库存不足,回退库存
$redis->incrBy('goods_id', num);
}
判断redis 里缓存的库存计数器, 如果库存充足 > 0的情况下进入到创建订单逻辑
目前这种方式可以解决超卖,但是并发人多的时候会出现少卖的情况。怀疑是redis自减成功,但是
数据库创建订单失败【?】,正常创建失败会回退库存的,但是实际就是会产生不能回退库存的情况
如何才能保证redis库存与数据库库存一致
看你的伪代码,MySQL 操作和 Redis 操作不是原子性的,用了 Redis ,但没完全用
$redis->decrBy('goods_id', $num)
如果有两个进程在极短的时间内扣减成功,create_order()
里面逻辑处理得稍慢一点,在 MySQL 上就会有并发问题,如果 MySQL 更新库存没有加锁就有可能出现你说得问题建议 Redis 库存扣减成功后,扔一个队列,然后通过队列去扣减 MySQL 库存