thinkphp+redis+队列

2019年12月06日 阅读数:85
这篇文章主要向大家介绍thinkphp+redis+队列,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

1,安装redis,根据本身的php版本安装对应的redis扩展(此步骤简单的描述一下)php

  1.1,安装 php_igbinary.dll,php_redis.dll扩展此处须要注意你的php版本如图:ajax

  

  1.2,php.ini文件新增 extension=php_igbinary.dll;extension=php_redis.dll两处扩展redis

ok此处已经完成第一步redis环境搭建完成看看phpinfo数据库


项目中实际使用redis缓存

  2.1,第一步配置redis参数以下,redis安装的默认端口为6379: 服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
/* 数据库配置 */
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
/**
         * 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,秒杀的核心问题是在大并发的状况下不会超出库存的购买,这个就是处理的关键因此思路是第一步在秒杀类的先作一些基础的数据生成:并发

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
/**
     * 访问产品前先将当前产品库存队列
     * @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( "当前产品已经秒杀完!" );
         }
         
     }

  接下来要作的就是用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
/**
      * 抢购商品前处理当前会员是否进入队列
      * @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"  =>  "系统繁忙,请重试!" ));
         }
     }

  附加一个调试的函数,删除指定队列值:

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队列已释放!" );           
          }
      }