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读取数据库信息的几种方法
May 24 PHP
如何在symfony中导出为CSV文件中的数据
Oct 06 PHP
6种php上传图片重命名的方法实例
Nov 04 PHP
PHP采用自定义函数实现遍历目录下所有文件的方法
Aug 19 PHP
PHP类的反射用法实例
Nov 03 PHP
php判断类是否存在函数class_exists用法分析
Nov 14 PHP
PHP获取表单数据与HTML嵌入PHP脚本的实现
Feb 09 PHP
小程序微信退款功能实现方法详解【基于thinkPHP】
May 05 PHP
PHP实现的抓取小说网站内容功能示例
Jun 27 PHP
浅谈Laravel模板实体转义带来的坑
Oct 22 PHP
PHP调用QQ互联接口实现QQ登录网站功能示例
Oct 24 PHP
Laravel validate error处理,ajax,json示例
Oct 25 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设计模式 Proxy (代理模式)
2011/06/26 PHP
php在服务器执行exec命令失败的解决方法
2012/03/03 PHP
PHP5.3的垃圾回收机制(动态存储分配方案)深入理解
2012/12/10 PHP
php中数字0和空值的区别分析
2014/06/05 PHP
解决cPanel无法安装php5.2.17
2014/06/22 PHP
php的sso单点登录实现方法
2015/01/08 PHP
thinkPHP5.0框架API优化后的友好性分析
2017/03/17 PHP
PHP二维数组实现去除重复项的方法【保留各个键值】
2017/12/21 PHP
JavaScript Title、alt提示(Tips)实现源码解读
2010/12/12 Javascript
JavaScript回调(callback)函数概念自我理解及示例
2013/07/04 Javascript
jquery统计用户选中的复选框的个数
2014/06/06 Javascript
借助JavaScript脚本判断浏览器Flash Player信息的方法
2014/07/09 Javascript
jQuery中用dom操作替代正则表达式
2014/12/29 Javascript
jQuery实现友好的轮播图片特效
2015/01/12 Javascript
jquery UI Datepicker时间控件的使用方法(终结版)
2015/11/07 Javascript
javascript动态获取登录时间和在线时长
2016/02/25 Javascript
JQuery validate 验证一个单独的表单元素实例
2017/02/17 Javascript
ReactNative页面跳转Navigator实现的示例代码
2017/08/02 Javascript
vue结合element-ui使用示例
2019/01/24 Javascript
JS中注入eval, Function等系统函数截获动态代码
2019/04/03 Javascript
Vue scrollBehavior 滚动行为实现后退页面显示在上次浏览的位置
2019/05/27 Javascript
[01:10:16]DOTA2上海特级锦标赛B组资格赛#2 Fnatic VS Spirit第一局
2016/02/27 DOTA
[33:42]LGD vs OG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python常见加密模块用法分析【MD5,sha,crypt模块】
2017/05/24 Python
Python实现删除文件中含“指定内容”的行示例
2017/06/09 Python
Django框架的中的setting.py文件说明详解
2018/10/15 Python
Django unittest 设置跳过某些case的方法
2018/12/26 Python
python itsdangerous模块的具体使用方法
2020/02/17 Python
python except异常处理之后不退出,解决异常继续执行的实现
2020/04/25 Python
去除python中的字符串空格的简单方法
2020/12/22 Python
英国DVD和蓝光碟片购买网站:Zoom.co.uk(电影和电视)
2019/09/23 全球购物
一名老师的自我评价
2014/02/07 职场文书
应届毕业生如何写求职信
2014/02/16 职场文书
2014年班主任自我评价范文
2014/04/23 职场文书
回门宴新娘答谢词
2015/09/29 职场文书
Python实现简单的猜单词
2021/06/15 Python