事务锁或redis实现商品库存出现超卖或秒杀场景

20 篇文章 1 订阅

 事务锁实现超库存解决:

<?php
$pdo = new PDO('mysql:host=127.0.0.1;port=3306; dbname=test','root','123456');
$pdo->beginTransaction();//开启事务
$sql="select `number` from storage where id=1 for UPDATE ";//利用for update 开启行锁
$res = $pdo->query($sql)->fetch();
$number = $res['number'];
if($number>0)
{
  $sql ="insert into `order` VALUES (null,$number)";
  $order_id = $pdo->query($sql);
  if($order_id)
  {
    $sql="update storage set `number`=`number`-1 WHERE id=1";
    if($pdo->query($sql))
    {

      $pdo->commit();//提交事务
    }
    else
    {
      $pdo->rollBack();//回滚
    }

  }

  else
  {
    $pdo->rollBack();//回滚
  }

?>

 redis实现秒杀场景

<?php




/**
    * 访问产品前先将当前产品库存队列
    * @access public
    * @author bieanju
    */

  public function _before_detail(){
        $where['goods_id'] = $this->goods_id;
        $where['start_time'] = array("lt",time());
        $where['end_time'] =  array("gt",time());
        $goods = M("goods")->where($where)->field('goods_num,start_time,end_time')->find();
        !$goods && $this->error("当前秒杀已结束!");

        //当前库存数大于订单提交数
        if($goods['goods_num'] > $goods['order_num']){
            $redis = $this->connectRedis();
            $getUserRedis = $redis->hGetAll("{$this->user_queue_key}");//获取用户队列
            $gnRedis = $redis->llen("{$this->goods_number_key}");//获取可用库存数

            /* 如果没有会员进来队列库存 */
            if(!count($getUserRedis) && !$gnRedis){            
                for ($i = 0; $i < $goods['goods_num']; $i ++) {
                    $redis->lpush("{$this->goods_number_key}", 1);
                }
            }
            //库存进行队列
             
            //重新获取库存数量
            $resetRedis = $redis->llen("{$this->goods_number_key}");

            if(!$resetRedis){
                $this->error("系统繁忙,请稍后抢购!");
            }
                                                     }

        else{
            $this->error("当前产品已经秒杀完!");
           }
         
    }


    

    /**
     * 抢购商品前处理当前会员是否进入队列
     * @access public
     * @author bieanju
     *   接下来要做的就是用ajax来异步的处理用户点击购买按钮进行符合条件的数据进入购买的排队队列(如果当前用户没在当前产品用户的队列就进入排队并且pop一个库存队列,如果在就抛出,):

     */
    public function goods_number_queue(){
        //判断有无登录
        !$this->user_id && $this->ajaxReturn(array("status" => "-1","msg" => "请先登录"));

        $model = M("flash_sale");
        $where['goods_id'] = $this->goods_id;
        $goods_info = $model->where($where)->find();

        !$goods_info && $this->error("对不起当前商品不存在或已下架!"); 
        /* redis 队列 */  
        $redis = $this->connectRedis();
        /* 进入队列  */
        //库存数量
        $goods_number_key = $redis->llen("{$this->goods_number_key}");


//如果当前用户没在当前产品用户的队列就进入排队并且pop一个库存队列,如果在就抛出
  if (!$redis->hGet("{$this->user_queue_key}", $this->user_id)) {
                 $goods_number_key = $redis->lpop("{$this->goods_number_key}");
 }

        if($goods_number_key){
            // 判断用户是否已在队列
            if (!$redis->hGet("{$this->user_queue_key}", $this->user_id)) {
                // 插入抢购用户信息
                $userinfo = array(
                    "user_id" => $this->user_id,
                    "create_time" => time()
                );        

                $redis->hSet("{$this->user_queue_key}", $this->user_id, serialize($userinfo));

                 $goods_number_key = $redis->lpop("{$this->goods_number_key}");

                $this->ajaxReturn(array("status" => "1"));
            }
            else{ // 如果用户在队列就购物车操作下单
                $modelCart = M("cart");
                $condition['user_id'] = $this->user_id;
                $condition['goods_id'] = $this->goods_id;
                $condition['prom_type'] = 1;
        $cartlist = $modelCart->where($condition)->count();
                if($cartlist>0){
                    $this->ajaxReturn(array("status" => "2"));
                }
                else{
                   $this->ajaxReturn(array("status" => "1"));
                }
                 
            }
             
        }
        else{
            $this->ajaxReturn(array("status" => "-1","msg" => "系统繁忙,请重试!"));
        }
    }


}
?>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值