php+redis实现商城秒杀功能详解

2018-07-03 22:23:03 织梦安装使用
  • 文章介绍
学习与分享 PHP自学中心


点击上面关注我关注我哟

小编 隔天推送php教程php技巧php视频教程MySQL笔试题等诸多优质内容,最接地气、重服务的本地微信平台!关注我们妥妥没错!

(商务合作联系QQ号:2230304070


文章来自:脚本之家

http://www.jb51.net/article/134662.htm


这篇文章主要为大家详细介绍了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: 

1
2
3
4
5
6
7
8
9
10
11
1
<?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
0
1
/**
    * 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
0
1
//现在初始化里面定义后边要使用的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
/**
  * 访问产品前先将当前产品库存队列
  * @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
/**
   * 抢购商品前处理当前会员是否进入队列
   * @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
0
1
2
3
4
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和JAVA谁才是世界上最好的语言..

    下一篇: PHP设计模式 — 访问者模式(Visit..

    相关文档推荐

    精品模板推荐

     2020-07-29   18166  0金币下载

     2020-07-27   65338  0金币下载

     2020-07-27   65333  0金币下载

     2020-06-22   57995  0金币下载

     2020-06-13   62585  0金币下载

     2020-06-13   62587  0金币下载

    专业的织梦模板定制下载站,在线购买后即可下载!

    商业源码

    跟版网模板,累计帮助5000+客户企业成功建站,为草根创业提供助力!

    立刻开启你的建站之旅
    
    QQ在线客服

    服务热线

    织梦建站咨询