类似商城的秒杀场景,大家肯定都遇到过。如何处理好秒杀时候商品的库存限制问题,真的一直让人头大。
常见的处理方案不外乎下面两种:
1、锁
表锁、行锁、文件锁。将需要操作的商品数据锁定,当前用户购买成功后,释放锁,允许其他用户操作该条数据。
2、队列
将请求放入队列中,也就是所有的请求都进行排队等待,按照顺序依次处理。并发请求都放到队列中,由额外进程串行处理,并发问题就不存在了,但是要额外进程支持以及处理延迟严重。
以上两种方案都避免不了“等待”的问题,高并发极端场景下,很可能会造成系统响应异常。暂时不对这两种方案作详解。
最近在学习 redis,发现可以结合 redis 的事物和 watch 命令巧妙解决超卖的问题。
老规矩,使用 watch 之前先来了解下它的特性。毕竟使用场景是以事物的特性为基础的。
watch 命令可以监控一个或多个键,一旦其中一个键被修改或删除,之后的事物就不会执行。监控一直持续到 exec 命令。
话不多说,直接上代码。
$redis = JRedis::getInstance(); $key = 'saleCount:id:3'; $redis->watch($key); //销量 $sales = $redis->get($key); //库存 $qty = 8; if ($sales >= $qty) { exit("已售罄"); } //开启事务 $redis->multi(); $redis->incrby($key, 1); $result = $redis->exec(); if ($result) { //执行数据库的销量增加操作,执行订单创建等操作 exit("校验成功,开始数据库操作"); } else { $redis->incrby($key, -1); exit("重新下单"); }
亲测效果杠杠的,而且就效率来说,要优于锁和队列。而且,还可以使用 redis 分摊数据库的压力,岂不是美滋滋。
5分推荐。
好文章分享:
https://zhuanlan.zhihu.com/p/269746986
https://zhuanlan.zhihu.com/p/336113193