基于Redis的PHP+MySQL商品秒杀与超卖场景基础解决方法

基于Redis的PHP+MySQL商品秒杀与超卖场景基础解决方法,简单来说,就是这样方法应用于简单的非超大型

的业务场景。超大型的秒杀业务往往需要考虑的情况比较多。

实现原理
把商品库存数量加到redis队列的num里,下单的时候通过rpop从队列中每次取1件商品,当num为0时,停止下单。
下面我们来看具体实现过程。这样就可以把压力主要甩给redis了。
加入库存队列
我们在Redis中加入商品库存队列。假如商品Apple iPhone 11库存有100件。我们可以写个脚本将商品库存加入到Redis队列中。

for($i=1; $i <= 100; $i++){
    $redis->lpush('num', $i);
}
下单购买
我们建立下单文件Order.php
首先是连接redis和mysql的代码。这个简单。

抢购下单是我们从商品可以中取出商品信息,然后从redis队列num中rpop出列一个商品数,接着马上处理商品购买的过程。

// 抢购下单
    public function goodsOrder()
    {
        $redis = self::Redis();
        $db = self::mysql();
        $goodsId = 1;
        $sql = "select id,inventory,price from hw_goods where id=".$goodsId;
        $stmt = $db->query($sql);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        $redis = self::Redis();
        $count = $redis->rpop('num');//每次从num取出1
        if($count == 0){
            $this->log(0, 'no num redis');
            echo '已没有库存';
        } else {
            $this->doOrder($row, 1);
        }
    }
如果redis队列数量变成0了,就是没有库存了,这个时候不做订单处理了,如果不是0就要更新库存,生成订单。
public function doOrder($goods, $goodsNum)
    {
        $orderNo = $this->orderNo();
        $number = $goods['inventory'] - $goodsNum;
        if ($number < 0) {
            $this->log(0, '已没有库存');
            echo '已没有库存';
            return false;
        }

        $db = self::mysql();
        try {
            $db->beginTransaction(); //启动事务
            $sql = "INSERT INTO `hw_order` (user_id,order_sn,status,goods_id,o_num,price,created_at) VALUES (:user_id,:order_sn,:status,:goods_id,:sku_id,:o_num,:price,:created_at)";
            $stmt = $db->prepare($sql);
            $stmt->execute([
                ':user_id' => rand(1, 500),
                ':order_sn' => $orderNo,
                ':status' => 1,
                ':goods_id' => $goods['id'],
                ':o_num' => $goodsNum,
                ':price' => $goods['price'] * 100,
                ':created_at' => date('Y-m-d H:i:s'),
            ]);

            $sql2 = "update hw_goods set inventory=inventory-".$goodsNum." where inventory>0 and id=".$goods['id'];
            $res = $db->exec($sql2);
            
            $db->commit(); //提交事务
            $this->log(1, '下单和库存扣减成功');
        } catch (Exception $e) {
            $db->rollBack(); //回滚事务
            $this->log(0, '下单失败');
        }
    }
这样就ok,整体逻辑比较简单,实现方法也比较简单。当变为0之后,就可以返回给用户其他等待页面了。

过几分钟,就直接提示没抢到,就oK了。。


关键词: 商品秒杀

上一篇: Centos7安装Cockpit教程,监控/管理Linux服务器
下一篇: 发现一只小php木马后门,挺特的,可以绕过部分查杀系统

目前还没有人评论,您发表点看法?
发表评论

评论内容 (必填):