php+redis實作商城秒殺功能案例分析(附程式碼)

php中世界最好的语言
發布: 2023-03-26 18:56:01
原創
2224 人瀏覽過

這次帶給大家php redis實現商城秒殺功能案例分析(附程式碼),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; => 'Redis_',//缓存前缀
  'DATA_CACHE_TYPE'=>'Redis',//默认动态缓存为Redis
  'DATA_CACHE_TIMEOUT' => false,
  'REDIS_RW_SEPARATE' => true, //Redis读写分离 true 开启
  'REDIS_HOST'=>'127.0.0.1', //redis服务器ip,多台用逗号隔开;读写分离开启时,第一台负责写,其它[随机]负责读;
  'REDIS_PORT'=>'6379',//端口号
  'REDIS_TIMEOUT'=>'300',//超时时间
  'REDIS_PERSISTENT'=>false,//是否长连接 false=短连接
  'REDIS_AUTH'=>'',//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",'0','intval');   
    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['uid'];   
  }
登入後複製

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

/**
  * 访问产品前先将当前产品库存队列
  * @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[&#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['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}");
    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['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" => "系统繁忙,请重试!"));
    }
  }
登入後複製

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

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

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

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

相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!

推薦閱讀:

PHP的RSA加密解密與開發介面案例使用分析

PHP長連線使用案例分析

#

以上是php+redis實作商城秒殺功能案例分析(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板