詳解thinkphp+redis+隊列的實現代碼(邏輯理解)

https://www.jb51.net/article/121729.html      核心在於 隊列只有一條 不會因查詢    併發。

1,安裝Redis,根據本身的PHP版本安裝對應的redis擴展(此步驟簡單的描述一下)php

1.1,安裝 php_igbinary.dll,php_redis.dll擴展此處須要注意你的php版本如圖:html

  

1.2,php.ini文件新增 extension=php_igbinary.dll;extension=php_redis.dll兩處擴展ajax

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

項目中實際使用redisthinkphp

2.1,第一步配置redis參數以下,redis安裝的默認端口爲6379: 緩存


1
2
3
4
5
6
7
8
9
10
11
12
13
14

return array (
  'DATA_CACHE_PREFIX' => '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:服務器

1
2
3
4
5
6
7
8
9
10
11
  private function connectRedis(){
   $redis = new \Redis();
   $redis ->connect(C( "REDIS_HOST" ),C( "REDIS_PORT" )); 
   return $redis ;
  }

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


1
2
3
4
5
6
7
8
9
10
11
//如今初始化裏面定義後邊要使用的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以下:
異步


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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 <</code> $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( "當前產品已經秒殺完!" );
  }
   
}

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  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 = $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" => "系統繁忙,請重試!" ));
   }
  }

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
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隊列已釋放!" );  
   }
  }
相關文章
相關標籤/搜索