最新公告
  • 欢迎您光临码农资源网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!加入我们
  • PHP用redis解决超卖的问题

    在商品秒杀活动中,比如商品库存只有100,但是在抢购活动中可能有200人同时抢购,这样就出现了并发,在100件商品下单完成库存为0了还有可能继续下单成功,就出现了超卖。

    为了解决这个问题,今天我主要用redis队列的方式处理。redis有list类型,list类型其实就是一个双向链表。通过lpush,pop操作从链表的头部或者尾部添加删除元素。这使得list即可以用作栈,也可以用作队列。先进先出,一端进,一端出,这就是队列。在队列里前一个走完之后,后一个才会走,所以redis的队列能完美的解决超卖并发的问题。

    实现原理:

    将商品库存循环lpush到num里,然后在下单的时候通过rpop每次取出1件商品,当num的值为0时,停止下单。

    数据表:

    订单表

    CREATETABLE`ims_order` ( `id`int(11) NOTNULL AUTO_INCREMENT, `order_sn`char(32) NOTNULL, `user_id`int(11) NOTNULL, `status`int(11) NOTNULLDEFAULT'0', `goods_id`int(11) NOTNULLDEFAULT'0', `sku_id`int(11) NOTNULLDEFAULT'0', `number`int(11) NOTNULL, `price`int(10) NOTNULLCOMMENT'价格:单位为分', `create_time`timestampNOTNULLDEFAULTCURRENT_TIMESTAMP,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5820DEFAULTCHARSET=utf8 COMMENT='订单表'

    商品表

    CREATETABLE`ims_hotmallstore_goods` ( `id`int(11) unsignedNOTNULL AUTO_INCREMENT, `name`varchar(50) NOTNULLCOMMENT'商品名称', `type_id`int(11) NOTNULLCOMMENT'商品分类', `img`textNOTNULLCOMMENT'商品图片', `money`decimal(10,2) NOTNULLCOMMENT'售价', `money2`decimal(10,2) NOTNULLCOMMENT'原价', `is_show`int(11) NOTNULLDEFAULT'1'COMMENT'1.上架2.下架', `uniacid`int(11) NOTNULLCOMMENT'小程序id', `inventory`int(11) NOTNULLCOMMENT'库存', `details`textNOTNULLCOMMENT'详情', `store_id`int(11) NOTNULLCOMMENT'商家id', `sales`int(11) NOTNULLCOMMENT'销量', `logo`varchar(100) NOTNULL, `num`int(11) NOTNULL, `is_gg`int(11) NOTNULLDEFAULT'2'COMMENT'是否开启规格',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2DEFAULTCHARSET=utf8

    日志表

    CREATETABLE`ims_order_log` ( `id`int(11) NOTNULL AUTO_INCREMENT, `status`int(11) NOTNULLDEFAULT'0', `msg`textCHARACTERSET utf8, `create_time`timestampNOTNULLDEFAULTCURRENT_TIMESTAMP,
      PRIMARY KEY (`id`), KEY`status` (`status`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4562DEFAULTCHARSET=gb2312 COMMENT='订单日志表'

    代码:

    classTest{ privatestatic $instance = null; // 用单列模式 实例化RedispublicstaticfunctionRedis(){ if (self::$instance == null) {
                $redis=new Redis();
                $redis->connect('127.0.0.1',6379); self::$instance = $redis;
            } returnself::$instance;
        } // 将商品库存循环到lpush的num里publicfunctiondoPageSaveNum(){
            $redis=self::Redis();
            $goods_id=1;
            $sql="select id, num, money from ims_hotmallstore_goods where id=".$goods_id;
            $goods=pdo_fetch($sql); if(!empty($goods)){ for($i=1; $i<=$goods['num']; $i++){
                 $redis->lpush('num',$i);
             } die('成功!');
            }else{ $this->echoMsg(0,'商品不存在。');
            }
        } // 抢购下单publicfunctiondoPageGoodsStore(){       
                $goods_id=1;
                $sql="select id, num, money from ims_hotmallstore_goods where id=".$goods_id;
                $goods=pdo_fetch($sql);
                $redis=self::Redis();
                $count=$redis->rpop('num');//每次从num取出1if($count==0){ $this->echoMsg(0,'no num redis');
                } $this->doPageGoodsOrder($goods,1);
                
        } // 保存日志publicfunctionechoMsg($status,$msg,$_data=""){ 
          
            $data=json_encode(array('status'=>$status,'msg'=>$msg,'data'=>$_data),JSON_UNESCAPED_UNICODE);
            $order_log['status']=$status;
            $order_log['msg']=$msg;
            $order_log['create_time']=time();
            pdo_insert('order_log',$order_log); die($data);
        } publicfunctionorderNo(){ return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);  
        } // 下单更新库存publicfunctiondoPageGoodsOrder($goods,$goods_number){   
            $orderNo=$this->orderNo();
            $number=$goods['num']-$goods_number; if($number<0){ $this->echoMsg(0,'已没有库存');
            }
            $user_id=rand(1,500);
            $order['user_id']=$user_id;
            $order['goods_id']=$goods['id'];
            $order['number']=$goods_number;
            $order['price']=$goods['money'];
            $order['status']=1;
            $order['sku_id']=2;
            $order['order_sn']=$orderNo;
            $order['create_time']=date('Y-m-d H:i:s');
            pdo_insert('order',$order);
            $sql="update ims_hotmallstore_goods set num=num-".$goods_number." where num>0 and id=".$goods['id'];
            $res=pdo_query($sql); if(!empty($res)){ $this->echoMsg(1,'库存扣减成功'.$number);
            }
            $redis=self::Redis();
            $redis->lpush('num',$goods_number); $this->echoMsg(0,'库存扣减失败'.$number);
    
        }
     } // 调用--将商品库存循环到lpush的num里if($_GET['i']==1){
       $model = new Test;
       $model->doPageSaveNum();
    } // 调用--高并发抢购下单if($_GET['i']==2){
       $model = new Test;
       $model->doPageGoodsStore();
    }
    想要了解更多内容,请持续关注码农资源网,一起探索发现编程世界的无限可能!
    本站部分资源来源于网络,仅限用于学习和研究目的,请勿用于其他用途。
    如有侵权请发送邮件至1943759704@qq.com删除

    码农资源网 » PHP用redis解决超卖的问题
    • 7会员总数(位)
    • 25846资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 293稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情