• php商城下单,可以购买多件商品,redis防高并发


    <?php
    header('content-type:text/html;charset=utf-8');
    echo time();
    class SeckillRedis {
        static protected $validity_time = 300; // 有效期 5分钟
     protected $goods_id;
     protected $user_queue_key;
     protected $goods_number_key;
     protected $user_id;

     public function __construct($goods_id,$area_id,$uid){
      if($goods_id){
       $this->goods_id=$goods_id;
       //当前商品队列的用户情况
       $this->user_queue_key="goods_".$goods_id."_user";
       //当前商品的库存队列
       $this->goods_number_key="goods_".$goods_id;
      }
      $this->user_id=$uid ? $uid : 2;
     }
     
     /* redis链接 */
     static public function getRedis(){
      $redis=new Redis();
      $redis->connect('127.0.0.1','6379') or die('Can not Content Redis');
      if($redis){
       return $redis;
      }else{
       die('Can not Content Redis!');
      }
     }
     // 添加或改变库存时初始化队列
     public function kuCun($num){
      $redis=$this->getRedis();
      $redis->delete($this->goods_number_key);
      $redis->delete($this->user_queue_key);
      for ($i=0; $i < $num; $i++) {
       $redis->rPush($this->goods_number_key, 1);
      }
     }
     // 判断未支付订单是否过期 ,定时更新秒杀商品入口人数
     public function poling_set_seckill_redis(){
      $redis=$this->getRedis();
      //exists检查key是否存在是否有值,存在返回1,不存在返回0,0也属于不存在的
      if($redis->exists($this->user_queue_key) == true){
       // 清除过期的使用数量
       $use_list = $redis->lRange($this->user_queue_key, 0, -1);
       
       foreach ($use_list as $k => $v) {
        $data = json_decode($v, true);
        if(time() - $data['time'] > self::$validity_time){
         var_dump($v.'ww');
         // 超过有效期 删除
         // $this->returnFree($k,$data['uid'],$data['num']);
         $value = $redis->lGet($this->user_queue_key,$k);
         
         if(!empty($value)){
         // var_dump($value.'hh');
        //这里体现出来lrem的延迟性了,所以不用lrem
        //$del=$redis->lrem($this->goods_number_key,$value,1);
          $del=$redis->lpop($this->user_queue_key);
          if($del!=''){
           // 添加空闲数量
           for ($i=0; $i < $data['num']; $i++) {
            $redis->rPush($this->goods_number_key, 1);
           }
          }
           
          // $sql语句,库存加1
          // return array('result' => true);
         }else{
          return array('result' => false, 'message' => '抢购信息:不存在索引');
         }
        }
       }
      }
     }
     
     /* 获取空闲抢购--num:购买件数 */
     public function getFree($num){
      if(empty($this->user_id)){
       return array('result' => false, 'message' => '抢购信息:用户ID不能为空');
      }
      $redis = self::getRedis();
      if($redis->llen($this->goods_number_key)=='0'){
       return array('result' => false, 'message' => '抢购信息:被抢光啦');
      }
      //可能并发大的有漏掉进去的
      if($redis->llen($this->goods_number_key) >= $num){
       file_put_contents('bb.log',var_export('123',true),FILE_APPEND);
      //用下面的循环,漏掉的订单过来,会减少库存量
       // for ($i=0; $i < $num; $i++) {
       //  $result = $redis->lPop($this->goods_number_key);
       // }
      //不得已用lrem
       $result = $redis->lrem($this->goods_number_key,'1',$num);
       // var_dump($redis->lrange($seckill_array[$type]['free_key'],0,-1));
       if($result == true){
        // 添加使用数量
        $index = $redis->rPush($this->user_queue_key, json_encode(array('uid' => $this->user_id, 'time' => time(),'num' => $num))) - 1;
        return array('result' => true, 'index' => $index);
       }else{
        return array('result' => false, 'message' => '抢购信息:被抢光啦');
       }
      }else{
       return array('result' => false, 'message' => '抢购信息:库存不够');
      }
       
     }
     /* 返回空闲抢购--$index为键值 */
     public function returnFree($index,$uid,$num){
      $redis = self::getRedis();
      $value = $redis->lGet($this->user_queue_key,$index);
      var_dump($value.'hh');
      if(!empty($value)){
       $redis->lRem($this->user_queue_key, $value, 1);
       // 添加空闲数量
       for ($i=0; $i < $num; $i++) {
        $redis->rPush($this->goods_number_key, 1);
       }
       
       // $sql语句,库存加1
       // return array('result' => true);
      }else{
       return array('result' => false, 'message' => '抢购信息:不存在索引');
      }
     }
    }

    class Index{
     
     /* 某个需要控制并发的控制器方法 */
     public function getOrderInfo(){
      $uid=mt_rand(1,100);
      $num=mt_rand(1,5);
      $miaosha=new SeckillRedis('3','123',$uid);
      // $miaosha->kuCun('20');
      $miaosha->poling_set_seckill_redis();
      $result = $miaosha->getFree('3');
      return $result;
      if($result['result'] == false){
       // 没有机会 返回错误信息
       return '网络繁忙,请重试';
      }
      // 处理数据库代码

     }
    }
    $hua = new Index;
    var_dump($hua->getOrderInfo()).'<br>';

     尽量不要用lrem命令,因为这个命令有延迟,影响高并发过程,尽量用rpush、lpop等命令

  • 相关阅读:
    密码等级
    ie兼容透明
    分割线
    支付宝银行判断接口
    date只能选择今天之后的时间js
    离开页面之前提示,关闭,刷新等
    使用 Linux 系统的常用命令
    C#窗体简单增删改查
    1
    二维数组
  • 原文地址:https://www.cnblogs.com/hualingyun/p/9438686.html
Copyright © 2020-2023  润新知