php下用redis解决秒杀超卖问题

来源:GK导航    date:2022-9-6    标签:,     admin

秒杀超卖问题,就是有一个商品抢购活动,一个商品假如有100件库存,但是在抢购时有200人来抢购,这时就会并发,原本只有100的库存但是抢购的人过多,就会发生数据库里原本只有100的库存但是库存为0的时候还会有人提交成功,这就是超卖。

  今天简单的用redis的队列来解决超卖问题。因为redis有list类型,list类型其实就是一个双向链表。通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。先进先出  一端进  一端出这就是队列。这里用redis就解决了并发的问题,在队列里前一个走完之后,后一个才会走。

  实现原理

   将库存循环lpush进一个redis值goods_number里去,然后在下单的时候依次rpop出来。这样就是下一个单取出来一个,然后等goods_number的值为0时,停止下单。

  首先建立三个表 store商品表  order订单表  log日志表

CREATE TABLE `store` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `goods_id` int(11) NOT NULL,   `sku_id` int(10) unsigned NOT NULL DEFAULT '0',   `number` int(10) NOT NULL DEFAULT '0',   `freez` float(11,2) NOT NULL DEFAULT '0.00' COMMENT '虚拟库存',   `price` int(10) NOT NULL COMMENT '价格:单位为分',   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='库存';    CREATE TABLE `order` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `order_sn` char(32) NOT NULL,   `user_id` int(11) NOT NULL,   `status` int(11) NOT NULL DEFAULT '0',   `goods_id` int(11) NOT NULL DEFAULT '0',   `sku_id` int(11) NOT NULL DEFAULT '0',   `number` int(11) NOT NULL,   `price` int(10) NOT NULL COMMENT '价格:单位为分',   `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4743 DEFAULT CHARSET=utf8 COMMENT='订单表';    CREATE TABLE `order` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `order_sn` char(32) NOT NULL,   `user_id` int(11) NOT NULL,   `status` int(11) NOT NULL DEFAULT '0',   `goods_id` int(11) NOT NULL DEFAULT '0',   `sku_id` int(11) NOT NULL DEFAULT '0',   `number` int(11) NOT NULL,   `price` int(10) NOT NULL COMMENT '价格:单位为分',   `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4743 DEFAULT CHARSET=utf8 COMMENT='订单表';

代码如下:

<?php namespace HomeController; use ThinkCacheDriverRedis; use ThinkController;  class TestController extends Controller {     public function index()     {         $wheres = array();         $wheres['goods_id'] = 1;         $number = M('store')->where($wheres)->getField('number');         $redis = new Redis();         for ($i = 0; $i < $number; $i++) {             $redis->lpush('goods_number', 1);         }         echo $redis->llen('goods_number');     }      //生成唯一订单号       function build_order_no()     {         return date('ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);     }     //记录日志       function insertLog($event, $type = 0)     {         $data['event'] = $event;         $data['type']  = $type;         $res = M('log')->add($data);     }      //模拟下单操作       //下单前判断redis队列库存量       function order()     {         $sku_id  = 11;  //传入已知的sku_id;          $wheres = array();         $wheres['sku_id'] = $sku_id;         $good_info = M('store')->where($wheres)->find();          $user_id  = rand(1, 200);         $goods_id = $good_info['goods_id'];         $price    = $good_info['price'];         $number   = 1; //抢购时每次买一件商品           $redis = new Redis();         $count = $redis->rpop('goods_number');  //下单时做rpop 从goods_number中取出1         if ($count == 0) {             $this->insertLog('error:no goods_number redis');             return;         }           if (($good_info['number'] - $number) <= 0) {             $this->insertLog('商品售罄');  //如果库存为0写入日志 并停止下单操作             return;         }           //生成订单             $order_sn = $this->build_order_no();          $data = array();         $data['order_sn'] = $order_sn;         $data['user_id']  = $user_id;         $data['goods_id'] = $goods_id;         $data['sku_id']   = $sku_id;         $data['number']   = $number;         $data['price']    = $price;          $order_rs = M('order')->add($data);          //库存减少           $wheres['sku_id'] = $sku_id;         $store_rs = M('store')->where($wheres)->setDec('number', $number);         if ($store_rs) {             $this->insertLog('库存减少成功');         } else {             $this->insertLog('库存减少失败');         }     } } 

先访问:/test/index 将redis的list初始化

然后可以访问:/test/order 进行模拟

腾讯云限时秒杀【点击购买】

搬瓦工,CN2高速线路,1GB带宽,电信联通优化KVM,延迟低,速度快,建站稳定,搬瓦工BandwagonHost VPS优惠码BWH26FXH3HIQ,支持<支付宝> 【点击购买】!

Vultr$3.5日本节点,512M内存/500G流量/1G带宽,电信联通优化,延迟低,速度快【点击购买】!

阿里云香港、新加坡VPS/1核/1G/25G SSD/1T流量/30M带宽/年付¥288【点击购买】

php下用redis解决秒杀超卖问题

`微信`扫码 加好友