Thinkphp5+Redis实现商品秒杀代码实例讲解


Posted in PHP onDecember 29, 2020

环境:wamp,redis

要求:安装WAMP,Redis,以及为PHP安装Redis扩展

秒杀功能大致思路:获取缓存列表的长度,如果长度(llen)等于0,就停止秒杀,即秒杀失败,如果长度大于0,则继续运行,先从缓存中移除一个元素(lpop),再进行数据库操作(添加订单表,商品库存数量减一),如果再进一个人秒杀,就再走一遍流程,循环往复。

一、安装Redis扩展

1.查看PHP版本信息

打开phpinfo.php,查看PHP版本,我的是PHP7.3.4,还有一个需要注意Architecture x64

Thinkphp5+Redis实现商品秒杀代码实例讲解

2.下载扩展文件

https://pecl.php.net/package/redis

https://pecl.php.net/package/igbinary

根据自己环境,选择合适的版本

3.解压

解压下载的压缩包,并把php_redis.dll、php_redis.pdb和php_igbinary.dll、php_igbinary.pdb四个文件,移至自己PHP版本对应目录下的ext文件夹下E:\phpstudy_pro\Extensions\php\php7.3.4nts\ext

Thinkphp5+Redis实现商品秒杀代码实例讲解

Thinkphp5+Redis实现商品秒杀代码实例讲解

4.修改php.ini

添加如下代码:

extension=php_igbinary.dll
extension=php_redis.dll

如果有这两句可以把前面的分号删掉,没有就自己添加上,要注意顺序,php_igbinary.dll 要在php_redis.dll 前面

Thinkphp5+Redis实现商品秒杀代码实例讲解

5.重启Apache

重启后,再运行phpinfo.php,查看是否安装成功

Thinkphp5+Redis实现商品秒杀代码实例讲解

二、数据结构

一共三张表,ab_goods商品表,ab_order订单表,ab_log日志表

商品表

Thinkphp5+Redis实现商品秒杀代码实例讲解

订单表

Thinkphp5+Redis实现商品秒杀代码实例讲解

日志表 记录秒杀信息

Thinkphp5+Redis实现商品秒杀代码实例讲解

三、代码

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;
use think\cache\driver\Redis;

class Miaosha extends Controller
{

 private $redis = null;
 private $cachekey = null; //缓存变量名
 private $basket = []; //私有数组,存放商品信息

 private $store = 50;

 /**
 * 购物车初始化,传入用户id
 */
 public function __construct()
 {
 parent::__construct();

 $this->redis = new \Redis(); // 实例化
 $this->redis->connect('127.0.0.1','6379');
 $this->redis->auth('zxf123456');

 }

 /**
 * 秒杀初始化
 */
 public function Ms_init()
 {
 // 删除缓存列表
 $this->redis->del($this->cachekey);

 $len = $this->redis->llen($this->cachekey);
 $count = $this->store - $len;

 for ($i=0; $i < $count; $i++) { 

 // 向库存列表推进50个,模拟50个商品库存
 $this->redis->lpush($this->cachekey,1);
 }

 echo "库存初始化完成:".$this->redis->llen($this->cachekey);
 }
 

 /**
 * 秒杀入口
 */
 public function index()
 {
 $id = 1; //商品编号
 
 if (empty($id)) {
 // 记录失败日志
 return $this->writeLog(0,'商品编号不存在'); 
 }

 // 计算库存列表长度
 $count = $this->redis->llen($this->cachekey);

 // 先判断库存是否为0,为0秒杀失败,不为0,则进行先移除一个元素,再进行数据库操作
 if ($count == 0) { //库存为0

 $this->writeLog(0,'库存为0');
 echo "库存为0";
 exit;

 }else{
 // 有库存
 //先移除一个列表元素
 $this->redis->lpop($this->cachekey);

 $ordersn = $this->build_order_no(); //生成订单
 $uid = rand(0,9999); //随机生成用户id
 $status = 1;
 // 再进行数据库操作
 $data = Db::table('ab_goods')->field('count,amount')->where('id',$id)->find(); //查找商品

 if (!$data) {
 return $this->writeLog(0,'该商品不存在');
 }

 $insert_data = [
 'order_sn' => $ordersn,
 'user_id' => $uid,
 'goods_id' => $id,
 'price' => $data['amount'],
 'status' => $status,
 'addtime' => date('Y-m-d H:i:s')
 ];

 // 订单入库
 $result = Db::table('ab_order')->insert($insert_data);
 // 自动减少一个库存
 $res = Db::table('ab_goods')->where('id',$id)->setDec('count');

 if ($res) {
 echo "第".$count."件秒杀成功";
 $this->writeLog(1,'秒杀成功');
 }else{
 echo "第".$count."件秒杀失败";
 $this->writeLog(0,'秒杀失败');
 }
 }
 }

 /**
 * 生成订单号
 */
 public function build_order_no()
 {
 return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
 }

 /**
 * 生成日志 1成功 0失败
 */
 public function writeLog($status = 1,$msg)
 {
 $data['count'] = 1;
 $data['status'] = $status;
 $data['addtime'] = date('Y-m-d H:i:s');
 $data['msg'] = $msg;
 return Db::table('ab_log')->insertGetId($data);
 }

}

四、压力测试

使用apache压力测试工具 AB 测试,模拟多用户秒杀商品,模拟60秒内发起3000个请求,并发600次,秒杀50个库存商品

AB测试相关参数说明

  • -r 指定接收到错误信息时不退出程序
  • -t 等待响应的最大时间
  • -n 指定压力测试总共的执行次数
  • -c 用于指定压力测试的并发数

1.初始化50个库存,运行ms_init方法

2.测试   命令行:

E:\phpstudy_pro\Extensions\Apache2.4.39\bin>ab -r -t 60 -n 3000 -c 1000 http://gouwuche.zxf/index/miaosha/index  

Thinkphp5+Redis实现商品秒杀代码实例讲解

3.检测数据库数据

Thinkphp5+Redis实现商品秒杀代码实例讲解

Thinkphp5+Redis实现商品秒杀代码实例讲解

日志表状态为1(秒杀成功)的数据有50人,订单表里的订单数也是50条,商品表里的商品数量变成了0(测试之前是50),商品秒杀成功完成!

如果不用redis而是直接用mysql的话,商品表订单的数量count会变成负数,而秒杀成功的人数也多余50人,订单表里的订单数量也多余50条(新测),下面是直接用Mysql的例子;

public function sqlMs()
 {
 $id = 1; //商品编号

 $count = 50;
 $ordersn = $this->build_order_no(); //生成订单
 $uid = rand(0,9999); //随机生成用户id
 $status = 1;
 // 再进行数据库操作
 $data = Db::table('ab_goods')->field('count,amount')->where('id',$id)->find(); //查找商品

 // 查询还剩多少库存
 $rs = Db::table('ab_goods')->where('id',$id)->value('count');
 if ($rs <= 0) {
 
 $this->writeLog(0,'库存为0');
 }else{

 $insert_data = [
 'order_sn' => $ordersn,
 'user_id' => $uid,
 'goods_id' => $id,
 'price' => $data['amount'],
 'status' => $status,
 'addtime' => date('Y-m-d H:i:s')
 ];

 // 订单入库
 $result = Db::table('ab_order')->insert($insert_data);
 // 自动减少一个库存
 $res = Db::table('ab_goods')->where('id',$id)->setDec('count');

 if ($res) {
 echo "第".$data['count']."件秒杀成功";
 $this->writeLog(1,'秒杀成功');
 }else{
 echo "第".$data['count']."件秒杀失败";
 $this->writeLog(0,'秒杀失败');
 }
 }
 }

到此这篇关于Thinkphp5+Redis实现商品秒杀的文章就介绍到这了,更多相关Thinkphp5+Redis实现商品秒杀内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
php access 数据连接与读取保存编辑数据的实现代码
May 12 PHP
PHP中=赋值操作符对不同数据类型的不同行为
Jan 02 PHP
php数组函数序列之array_sum() - 计算数组元素值之和
Oct 29 PHP
使用php+Ajax实现唯一校验实现代码[简单应用]
Nov 29 PHP
用php随机生成福彩双色球号码的2种方法
Feb 04 PHP
基于HBase Thrift接口的一些使用问题及相关注意事项的详解
Jun 03 PHP
yii2利用自带UploadedFile实现上传图片的示例
Feb 16 PHP
PHP SFTP实现上传下载功能
Jul 26 PHP
php连接mysql数据库最简单的实现方法
Sep 24 PHP
php测试kafka项目示例
Feb 06 PHP
Centos7安装swoole扩展操作示例
Mar 26 PHP
PHP中-&gt;和=&gt;的含义及使用示例解析
Aug 06 PHP
PHP序列化和反序列化深度剖析实例讲解
Dec 29 #PHP
PHP实现简单注册登录系统
Dec 28 #PHP
php的lavarel框架中join和orWhere的用法
Dec 28 #PHP
php中yar框架实例用法讲解
Dec 27 #PHP
php中数组最简单的使用方法
Dec 27 #PHP
用Laravel轻松处理千万级数据的方法实现
Dec 25 #PHP
PHP操作Redis常用命令的实例详解
Dec 23 #PHP
You might like
如何使用php输出时间格式
2013/08/31 PHP
php查询ip所在地的方法
2014/12/05 PHP
php结合正则获取字符串中数字
2015/06/19 PHP
js+FSO遍历文件夹下文件并显示
2007/03/07 Javascript
论坛里点击别人帖子下面的回复,回复标题变成“回复 24# 的帖子”
2009/06/14 Javascript
详解JavaScript函数绑定
2013/08/18 Javascript
对于Form表单reset方法的新认识
2014/03/05 Javascript
jQuery控制TR显示隐藏的几种方法
2014/06/18 Javascript
JavaScript实现的字符串replaceAll函数代码分享
2015/04/02 Javascript
JS非Alert实现网页右下角“未读信息”效果弹窗
2015/09/26 Javascript
javascript实现自动填写表单实例简析
2015/12/02 Javascript
js 判断一组日期是否是连续的简单实例
2016/07/11 Javascript
vue 中filter的多种用法
2018/04/26 Javascript
vue .sync修饰符的使用详解
2018/06/15 Javascript
vue.js多页面开发环境搭建过程
2019/04/24 Javascript
jQuery实现判断滚动条滚动到document底部的方法分析
2019/08/27 jQuery
vue+element table表格实现动态列筛选的示例代码
2021/01/14 Vue.js
Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息示例
2018/05/04 Python
python实现验证码识别功能
2018/06/07 Python
pandas把所有大于0的数设置为1的方法
2019/01/26 Python
django 控制页面跳转的例子
2019/08/06 Python
python 一维二维插值实例
2020/04/22 Python
日本运动品牌美津浓官方购物网站:MIZUNO SHOP
2016/08/21 全球购物
斯图尔特·韦茨曼鞋加拿大官网:Stuart Weitzman加拿大
2019/10/13 全球购物
opencv实现图像几何变换
2021/03/24 Python
电子信息专业自荐书
2014/02/04 职场文书
材料工程专业毕业生求职信
2014/03/04 职场文书
幼儿园家长寄语
2014/04/02 职场文书
人力资源管理系自荐信
2014/05/31 职场文书
商务英语专业求职信
2014/06/26 职场文书
先进班组事迹材料
2014/12/25 职场文书
索赔员岗位职责
2015/02/15 职场文书
2014年度个人总结范文
2015/03/09 职场文书
2015教师年度考核评语
2015/03/25 职场文书
MySQL创建索引需要了解的
2021/04/08 MySQL
python ansible自动化运维工具执行流程
2021/06/24 Python