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开发的一些注意点总结
Oct 12 PHP
PHP几个数学计算的内部函数学习整理
Aug 06 PHP
php 操作调试的方法
Jul 12 PHP
PHP小教程之实现链表
Jun 09 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(二)
Jun 23 PHP
如何用PHP来实现一个动态Web服务器
Jul 29 PHP
PHP7.0安装笔记整理
Aug 28 PHP
Symfony2实现在doctrine中内置数据的方法
Feb 05 PHP
解决yii2左侧菜单子级无法高亮问题的方法
May 08 PHP
PHP MYSQL简易交互式站点开发
Dec 27 PHP
PHP的mysqli_rollback()函数讲解
Jan 23 PHP
PHP使用CURL实现下载文件功能示例
Jun 03 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
实时抓取YAHOO股票报价的代码
2006/10/09 PHP
PHP数据类型的总结分析
2013/06/13 PHP
用PHP解决的一个栈的面试题
2014/07/02 PHP
重新认识php array_merge函数
2014/08/31 PHP
thinkphp 手机号和用户名同时登录
2017/01/20 PHP
如何打开php的gd2库
2017/02/09 PHP
javascript 动态调整图片尺寸实现代码
2009/12/28 Javascript
jQuery控制图片的hover效果(smartRollover.js)
2012/03/18 Javascript
提高javascript效率 一次判断,而不要次次判断
2012/03/30 Javascript
JS实现简单的Canvas画图实例
2013/07/04 Javascript
jquery 延迟执行实例介绍
2013/08/20 Javascript
javascript中打印当前的时间实现思路及代码
2013/12/18 Javascript
深入浅析JavaScript中with语句的理解
2016/05/12 Javascript
Web性能优化系列 10个提升JavaScript性能的技巧
2016/09/27 Javascript
Jquery EasyUI Datagrid右键菜单实现方法
2016/12/30 Javascript
Angular2下使用pdf插件的方法详解
2017/04/29 Javascript
nodejs multer实现文件上传与下载
2017/05/10 NodeJs
nodeJS实现简单网页爬虫功能的实例(分享)
2017/06/08 NodeJs
解决jquery appaend元素中id绑定事件失效的问题
2017/09/12 jQuery
angularJS实现动态添加,删除div方法
2018/02/27 Javascript
Vue 实现拖动滑块验证功能(只有css+js没有后台验证步骤)
2018/08/24 Javascript
vue中子组件的methods中获取到props中的值方法
2018/08/27 Javascript
vue实现点击隐藏与显示实例分享
2019/02/13 Javascript
js实现橱窗展示效果
2020/01/11 Javascript
node.JS事件机制与events事件模块的使用方法详解
2020/02/06 Javascript
wxPython窗口的继承机制实例分析
2014/09/28 Python
在Python中关于中文编码问题的处理建议
2015/04/08 Python
Python基于scrapy采集数据时使用代理服务器的方法
2015/04/16 Python
python实现微信小程序自动回复
2018/09/10 Python
pycharm实现print输出保存到txt文件
2020/06/01 Python
使用HTML5拍照示例代码
2013/08/06 HTML / CSS
HTML5 Canvas中绘制椭圆的4种方法
2015/04/24 HTML / CSS
陈安之励志演讲稿
2014/08/21 职场文书
教师党员学习群众路线心得体会
2014/11/04 职场文书
具结保证书范本
2015/05/11 职场文书
HTML速写之Emmet语法规则的实现
2021/04/07 HTML / CSS