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 相关文章推荐
php 代码优化的42条建议 推荐
Sep 25 PHP
PHP Zip压缩 在线对文件进行压缩的函数
May 26 PHP
PHP中文URL编解码(urlencode()rawurlencode()
Jul 03 PHP
PHP imagegrabscreen和imagegrabwindow(截取网站缩略图)的实例代码
Nov 07 PHP
百度ping方法使用示例 自动ping百度
Jan 26 PHP
php数组去除空值函数分享
Feb 02 PHP
教你识别简单的免查杀PHP后门
Sep 13 PHP
thinkPHP5.0框架独立配置与动态配置方法
Mar 17 PHP
PHP字典树(Trie树)定义与实现方法示例
Oct 09 PHP
PHP后台实现微信小程序登录
Aug 03 PHP
CI框架实现创建自定义类库的方法
Dec 25 PHP
PHP设计模式之 策略模式Strategy详解【对象行为型】
May 01 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 线程安全与非线程安全版本的区别深入解析
2013/08/06 PHP
PHP入门教程之正则表达式基本用法实例详解(正则匹配,搜索,分割等)
2016/09/11 PHP
PHP严重致命错误处理:php Fatal error: Cannot redeclare class or function
2017/02/05 PHP
PHP字典树(Trie树)定义与实现方法示例
2017/10/09 PHP
PHP实现的XXTEA加密解密算法示例
2018/08/28 PHP
php使用redis的有序集合zset实现延迟队列应用示例
2020/02/20 PHP
jquery动画2.元素坐标动画效果(创建一个图片走廊)
2012/08/24 Javascript
关于scrollLeft,scrollTop的浏览器兼容性测试
2013/03/19 Javascript
JSON序列化与解析原生JS方法且IE6和chrome测试通过
2013/09/05 Javascript
特殊情况下如何获取span里面的值
2014/05/20 Javascript
控制台报错object is not a function的解决方法
2014/08/24 Javascript
JavaScript中合并数组的N种方法
2014/09/16 Javascript
Angular中$compile源码分析
2016/01/28 Javascript
JavaScript实现99乘法表及隔行变色实例代码
2016/02/24 Javascript
Javascript Event(事件)的传播与冒泡
2017/01/23 Javascript
vue中如何引入jQuery和Bootstrap
2017/04/10 jQuery
浅谈angularjs中响应回车事件
2017/04/24 Javascript
JavaScript限制在客户区可见范围的拖拽(解决scrollLeft和scrollTop的问题)(2)
2017/05/17 Javascript
Nuxt的路由配置和参数传递方式
2020/11/06 Javascript
[01:14:05]《加油DOTA》第四期
2014/08/25 DOTA
python简单程序读取串口信息的方法
2015/03/13 Python
Django Admin中增加导出Excel功能过程解析
2019/09/04 Python
python GUI库图形界面开发之PyQt5切换按钮控件QPushButton详细使用方法与实例
2020/02/28 Python
Pycharm创建python文件自动添加日期作者等信息(步骤详解)
2021/02/03 Python
美国伴娘礼服商店:Evening Collective
2019/10/07 全球购物
九年级英语教学反思
2014/01/31 职场文书
上班看电影检讨书
2014/02/12 职场文书
体育课课后反思
2014/04/24 职场文书
小学生安全演讲稿
2014/04/25 职场文书
2014党支部对照检查材料思想汇报
2014/10/05 职场文书
2015年父亲节活动总结
2015/02/12 职场文书
上班迟到检讨书范文
2015/05/06 职场文书
感恩教师主题班会
2015/08/12 职场文书
2016年国庆节宣传标语
2015/11/25 职场文书
倡议书怎么写?
2019/04/11 职场文书
mysql中关键词exists的用法实例详解
2022/06/10 MySQL