首頁  >  文章  >  後端開發  >  php和redis實現商城秒殺功能代碼分享

php和redis實現商城秒殺功能代碼分享

小云云
小云云原創
2018-02-09 09:18:344658瀏覽

本文主要和大家介紹了php+redis實現商城秒殺功能,具有一定的參考價值,有興趣的小夥伴們可以參考一下,希望能幫助到大家。

1、安裝redis,依照自己的php版本安裝對應的redis擴充(此步驟簡單的描述一下)

1.1.安裝php_igbinary.dll,php_redis.dll擴充這裡需要注意你的php版本如圖:

1.2.php.ini檔案新增extension=php_igbinary.dll;extension=php_redis.dll兩處擴充功能

ok此處已經完成第一步redis環境搭建完成看看phpinfo

2、專案中實際使用redis

2.1.第一步設定redis參數如下,redis安裝的預設埠為6379: 


<?php
/* 数据库配置 */
return array(
  &#39;DATA_CACHE_PREFIX&#39; => &#39;Redis_&#39;,//缓存前缀
  &#39;DATA_CACHE_TYPE&#39;=>&#39;Redis&#39;,//默认动态缓存为Redis
  &#39;DATA_CACHE_TIMEOUT&#39; => false,
  &#39;REDIS_RW_SEPARATE&#39; => true, //Redis读写分离 true 开启
  &#39;REDIS_HOST&#39;=>&#39;127.0.0.1&#39;, //redis服务器ip,多台用逗号隔开;读写分离开启时,第一台负责写,其它[随机]负责读;
  &#39;REDIS_PORT&#39;=>&#39;6379&#39;,//端口号
  &#39;REDIS_TIMEOUT&#39;=>&#39;300&#39;,//超时时间
  &#39;REDIS_PERSISTENT&#39;=>false,//是否长连接 false=短连接
  &#39;REDIS_AUTH&#39;=>&#39;&#39;,//AUTH认证密码 
);
?>

2.2.實際函數中使用redis:


/**
    * redis连接
    * @access private
    * @return resource
    * @author bieanju
    */
  private function connectRedis(){
    $redis=new \Redis();
    $redis->connect(C("REDIS_HOST"),C("REDIS_PORT"));    
    return $redis;
  }

2.3. 秒殺的核心問題是在大並發的情況下不會超出庫存的購買,這個就是處理的關鍵所以思路是第一步在秒殺類的先做一些基礎的數據生成:


//现在初始化里面定义后边要使用的redis参数
public function _initialize(){
    parent::_initialize();
    $goods_id = I("goods_id",&#39;0&#39;,&#39;intval&#39;);   
    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 = $this->user_id ? $this->user_id : $_SESSION[&#39;uid&#39;];   
  }

2.4. 第二步是關鍵所在,使用者在進入商品詳情頁前先將目前商品的庫存進行佇列存入redis如下:


/**
  * 访问产品前先将当前产品库存队列
  * @access public
  * @author bieanju
  */
  public function _before_detail(){
    $where[&#39;goods_id&#39;] = $this->goods_id;
    $where[&#39;start_time&#39;] = array("lt",time());
    $where[&#39;end_time&#39;] = array("gt",time());
    $goods = M("goods")->where($where)->field(&#39;goods_num,start_time,end_time&#39;)->find();
    !$goods && $this->error("当前秒杀已结束!");
    if($goods[&#39;goods_num&#39;] > $goods[&#39;order_num&#39;]){
      $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[&#39;goods_num&#39;]; $i ++) {
          $redis->lpush("{$this->goods_number_key}", 1);
        }
      }
      $resetRedis = $redis->llen("{$this->goods_number_key}");
      if(!$resetRedis){
        $this->error("系统繁忙,请稍后抢购!");
      }
    }else{
      $this->error("当前产品已经秒杀完!");
    }
     
  }

接下來要做的就是用ajax來異步的處理用戶點擊購買按鈕進行符合條件的數據進入購買的排隊隊列(如果當前用戶沒在當前產品用戶的隊列就進入排隊並且pop一個庫存隊列,如果在就拋出,):


/**
   * 抢购商品前处理当前会员是否进入队列
   * @access public
   * @author bieanju
   */
  public function goods_number_queue(){
    !$this->user_id && $this->ajaxReturn(array("status" => "-1","msg" => "请先登录"));
    $model = M("flash_sale");
    $where[&#39;goods_id&#39;] = $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}");
    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));
        $this->ajaxReturn(array("status" => "1"));
      }else{
        $modelCart = M("cart");
        $condition[&#39;user_id&#39;] = $this->user_id;
        $condition[&#39;goods_id&#39;] = $this->goods_id;
        $condition[&#39;prom_type&#39;] = 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" => "系统繁忙,请重试!"));
    }
  }

附加一個調試的函數,刪除指定佇列值:


##

public function clearRedis(){
     set_time_limit(0);
     $redis = $this->connectRedis();
     //$Rd = $redis->del("{$this->user_queue_key}");
     $Rd = $redis->hDel("goods49",&#39;用户id&#39;&#39;);
     $a = $redis->hGet("goods_49_user", &#39;用户id&#39;);
     if(!$a){
       dump($a);
     }
     
     if($Rd == 0){
       exit("Redis队列已释放!");      
     }
   }

走到這裡的時候秒殺的核心基本上就完了,細節還需要自己在去完善,像購物車這邊的處理還有訂單的處理,好吧開始跑程序利用apache自身的ab可以進行簡單的模擬並發測試如下:

跑起來,我擦跑步起來redis沒有任何反應,此時還少一步重要的步驟就是開啟redis服務,請根據自己的系統下一個redisbin_x32或redisbin_x64的redis服務管理工具,點選redis-server.exe,ok至此全部完成如下圖:

##相關推薦:


#JS腳本實作網頁自動秒殺實例分享

Yii框架redis+php實作秒殺效果的實例分析

商城搶購秒殺防止庫存超賣

以上是php和redis實現商城秒殺功能代碼分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn