php+redis实现商城秒杀功能


Posted in PHP onNovember 19, 2020

好久没来整理文章了,闲了没事写篇文章记录下php+redis实现商城秒杀功能。

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

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

php+redis实现商城秒杀功能

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

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

php+redis实现商城秒杀功能

2、项目中实际使用redis

2.1.第一步配置redis参数如下,redis安装的默认端口为6379: 

<?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:

/**
  * 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['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一个库存队列,如果在就抛出,):

/**
  * 抢购商品前处理当前会员是否进入队列
  * @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可以进行简单的模拟并发测试如下:

php+redis实现商城秒杀功能

跑起来,我擦跑步起来redis没有任何反应,此时还少一步重要的步骤就是开启redis服务,请根据自己的系统下一个redisbin_x32或者redisbin_x64的redis服务管理工具,点击redis-server.exe,ok至此全部完成如下图:

php+redis实现商城秒杀功能

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
玩转虚拟域名◎+ .
Oct 09 PHP
小偷PHP+Html+缓存
Nov 25 PHP
php环境配置 php5 MySQL5 apache2 phpmyadmin安装与配置图文教程
Mar 16 PHP
php设计模式 Observer(观察者模式)
Jun 26 PHP
php设计模式之观察者模式的应用详解
May 21 PHP
thinkphp实现面包屑导航(当前位置)例子分享
May 10 PHP
ThinkPHP通过AJAX返回JSON的两种实现方法
Dec 18 PHP
PHP实现的简易版图片相似度比较
Jan 07 PHP
php获取网页里所有图片并存入数组的方法
Apr 06 PHP
PHP基于单例模式编写PDO类的方法
Sep 13 PHP
使用php完成常见的文件上传功能(推荐)
Jan 13 PHP
PHP设计模式之工厂方法设计模式实例分析
Apr 25 PHP
php+redis消息队列实现抢购功能
Feb 08 #PHP
PHP多线程模拟实现秒杀抢单
Feb 07 #PHP
PHP设计模式之装饰器模式实例详解
Feb 07 #PHP
PHP使用星号替代用户名手机和邮箱的实现代码
Feb 07 #PHP
PHP unlink与rmdir删除目录及目录下所有文件实例代码
Feb 07 #PHP
php删除一个路径下的所有文件夹和文件的方法
Feb 07 #PHP
浅析PHP类的反射来实现依赖注入过程
Feb 06 #PHP
You might like
饭制《星际争霸》Mod:优化游戏机制 增加新单位
2017/07/02 星际争霸
文件系统基本操作类
2006/11/23 PHP
PHP中函数内引用全局变量的方法
2008/10/20 PHP
PHP+SQL 注入攻击的技术实现以及预防办法
2011/01/27 PHP
destoon数据库表说明汇总
2014/07/15 PHP
php使用GD创建保持宽高比缩略图的方法
2015/04/17 PHP
PHP数组操作实例分析【添加,删除,计算,反转,排序,查找等】
2016/12/24 PHP
javascript引用对象的方法代码
2007/08/13 Javascript
js实现运行代码需要刷新的解决方法
2007/08/18 Javascript
js改变鼠标的形状和样式的方法
2014/03/31 Javascript
Javascript中的关键字和保留字整理
2014/10/16 Javascript
JavaScript中Math.SQRT2属性的使用详解
2015/06/14 Javascript
JS实现滑动菜单效果代码(包括Tab,选项卡,横向等效果)
2015/09/24 Javascript
JQuery获取鼠标进入和离开容器的方向
2016/12/29 Javascript
用nodeJS搭建本地文件服务器的几种方法小结
2017/03/16 NodeJs
详解从Node.js的child_process模块来学习父子进程之间的通信
2017/03/27 Javascript
利用原生JavaScript实现造日历轮子实例代码
2019/05/08 Javascript
vue多个元素的样式选择器问题
2019/11/29 Javascript
[58:59]完美世界DOTA2联赛PWL S3 access vs CPG 第一场 12.13
2020/12/16 DOTA
Python中的条件判断语句基础学习教程
2016/02/07 Python
Python读取系统文件夹内所有文件并统计数量的方法
2018/10/23 Python
Python实现剪刀石头布小游戏(与电脑对战)
2019/12/31 Python
tensorflow求导和梯度计算实例
2020/01/23 Python
Python基于read(size)方法读取超大文件
2020/03/12 Python
AmazeUI图片轮播效果的示例代码
2020/08/20 HTML / CSS
short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
2014/09/26 面试题
女大学生毕业找工作的自我评价
2013/10/03 职场文书
个人现实表现材料
2014/02/04 职场文书
工会优秀工作者事迹
2014/08/17 职场文书
领导干部群众路线剖析材料
2014/10/09 职场文书
公司员工安全协议书
2014/11/21 职场文书
2015年社区科普工作总结
2015/05/13 职场文书
穷人该怎么创业?谨记以下几点
2019/07/11 职场文书
pytorch实现线性回归以及多元回归
2021/04/11 Python
如何用JavaScript学习算法复杂度
2021/04/30 Javascript
Python时间操作之pytz模块使用详解
2022/06/14 Python