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 相关文章推荐
如何限制访问者的ip(PHPBB的代码)
Oct 09 PHP
一个高ai的分页函数和一个url函数
Oct 09 PHP
用PHP查询域名状态whois的类
Nov 25 PHP
PHP测试程序运行时间的类
Feb 05 PHP
json的键名为数字时的调用方式(示例代码)
Nov 15 PHP
php判断字符串在另一个字符串位置的方法
Feb 27 PHP
网站防止被刷票的一些思路与方法
Jan 08 PHP
PHP使用gmdate实现将一个UNIX 时间格式化成GMT文本的方法
Mar 19 PHP
详解PHP中的Traits
Jul 29 PHP
PHP会员找回密码功能的简单实现
Sep 05 PHP
详解PHP中的 input属性(隐藏 只读 限制)
Aug 14 PHP
PHP常用字符串函数小结(推荐)
Aug 05 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
PHP使用json_encode函数时不转义中文的解决方法
2014/11/12 PHP
在Linux系统下一键重新安装WordPress的脚本示例
2015/06/30 PHP
php实现编辑和保存文件的方法
2015/07/20 PHP
初识通用数据库操作类――前端easyui-datagrid,form(php)
2015/07/31 PHP
Yii2增删改查之查询 where参数详细介绍
2016/08/08 PHP
基于Laravel(5.4版本)的基本增删改查操作方法
2019/10/11 PHP
js修改原型的属性使用介绍
2014/01/26 Javascript
JavaScript中的公有、私有、特权和静态成员用法分析
2014/11/20 Javascript
Jquery网页内滑动缓冲导航的实现代码
2015/04/05 Javascript
javascript瀑布流式图片懒加载实例解析与优化
2016/02/23 Javascript
jQuery树形插件jquery.simpleTree.js用法分析
2016/09/05 Javascript
Jquery针对tr td的一些实用操作方法(必看篇)
2016/10/05 Javascript
Bootstrap的class样式小结
2016/12/01 Javascript
原生JS实现图片轮播切换效果
2016/12/15 Javascript
js 原型对象和原型链理解
2017/02/09 Javascript
Angular项目从新建、打包到nginx部署全过程记录
2017/12/09 Javascript
vue页面加载闪烁问题的解决方法
2018/03/28 Javascript
微信小程序canvas拖拽、截图组件功能
2018/09/04 Javascript
vue-router 手势滑动触发返回功能
2018/09/30 Javascript
[01:03:03]VP vs Mineski 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
使用Python编写一个模仿CPU工作的程序
2015/04/16 Python
在Python中操作列表之List.pop()方法的使用
2015/05/21 Python
python在Windows下安装setuptools(easy_install工具)步骤详解
2016/07/01 Python
Python实现的将文件每一列写入列表功能示例【测试可用】
2018/03/19 Python
使用python进行波形及频谱绘制的方法
2019/06/17 Python
Python代码需要缩进吗
2020/07/01 Python
html5 touch事件实现触屏页面上下滑动(二)
2016/03/10 HTML / CSS
Farfetch香港官网:汇集全球时尚奢侈品购物平台
2017/11/26 全球购物
LN-CC美国:伦敦时尚生活的缩影
2019/02/19 全球购物
语文教育专业推荐信范文
2013/11/25 职场文书
解除劳动合同协议书
2014/04/14 职场文书
2014村党支部书记党建工作汇报材料
2014/11/02 职场文书
社区法制宣传日活动总结
2015/05/05 职场文书
优质护理心得体会
2016/01/22 职场文书
JavaScript中的宏任务和微任务详情
2021/11/27 Javascript
python解析json数据
2022/04/29 Python