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 相关文章推荐
怎样在UNIX系统下安装MySQL
Oct 09 PHP
php在线代理转向代码
May 05 PHP
PHP5权威编程阅读学习笔记 附电子书下载
Jul 05 PHP
php cli 小技巧
Jun 03 PHP
解析PHP可变函数的经典用法
Jun 20 PHP
关于PHP模板Smarty的初级使用方法以及心得分享
Jun 21 PHP
php处理restful请求的路由类分享
Feb 27 PHP
PHP读取大文件的类SplFileObject使用介绍
Apr 09 PHP
php中curl和file_get_content的区别
May 10 PHP
php多文件打包下载的实例代码
Jul 12 PHP
Yii2框架redis基本应用示例
Jul 13 PHP
Yii Framework框架使用PHPExcel组件的方法示例
Jul 24 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 抓取网页图片并且另存为的实现代码
2010/03/24 PHP
CodeIgniter框架数据库事务处理的设计缺陷和解决方案
2014/07/25 PHP
php清除和销毁session的方法分析
2015/03/19 PHP
JS实现浏览器菜单命令
2006/09/05 Javascript
常用简易JavaScript函数
2009/04/09 Javascript
纯js实现背景图片切换效果代码
2010/11/14 Javascript
AngularJS身份验证的方法
2016/02/17 Javascript
深入理解javascript函数参数与闭包
2016/12/12 Javascript
JavaScript高阶函数_动力节点Java学院整理
2017/06/28 Javascript
JS实现电商放大镜效果
2017/08/24 Javascript
深入理解Angularjs 脏值检测
2018/10/12 Javascript
Bootstrap4 gulp 配置详解
2019/01/06 Javascript
vue和better-scroll实现列表左右联动效果详解
2019/04/29 Javascript
vue+elementUI动态生成面包屑导航教程
2019/11/04 Javascript
Vue实现简易计算器
2020/02/25 Javascript
Python编程pygal绘图实例之XY线
2017/12/09 Python
python 日期操作类代码
2018/05/05 Python
pyspark操作MongoDB的方法步骤
2019/01/04 Python
聊聊python里如何用Borg pattern实现的单例模式
2019/06/06 Python
对python中的控制条件、循环和跳出详解
2019/06/24 Python
远程部署工具Fabric详解(支持Python3)
2019/07/04 Python
Python_查看sqlite3表结构,查询语句的示例代码
2019/07/17 Python
Python帮你微信头像任意添加装饰别再@微信官方了
2019/09/25 Python
Python自动化测试笔试面试题精选
2020/03/12 Python
keras读取h5文件load_weights、load代码操作
2020/06/12 Python
小程序瀑布流解决左右两边高度差距过大的问题
2019/02/20 HTML / CSS
新西兰最大的在线设计师眼镜店:SmartBuyGlasses新西兰
2017/10/20 全球购物
哈萨克斯坦移动和数字技术在线商店:SatelOnline.kz
2020/09/04 全球购物
金士达面试非笔试
2012/03/14 面试题
文明青少年标兵事迹材料
2014/01/28 职场文书
党的群众路线调研报告
2014/11/03 职场文书
车队安全员岗位职责
2015/02/15 职场文书
结婚通知短信怎么写
2015/04/17 职场文书
如何写好闭幕词
2019/04/02 职场文书
oracle表分区的概念及操作
2021/04/24 Oracle
JS数组方法some、every和find的使用详情
2021/10/05 Javascript