转载:https://blog.csdn.net/qq_43164547/article/details/106595772
TP5秒杀高并发教程
介绍
测试环境
创建数据库和表
TP5的配置
编写代码
测试秒杀效果
总结
上一篇文章介绍了安装redis,那么这篇文章就介绍一下利用redis做一个简单高并发案例
win10 64位专业版
小皮面板
tp5.0框架
先新建名字为redistest的数据库
再将sql语句导入创建数据表和插入数据
/*
Navicat Premium Data Transfer
Source Server : 本地
Source Server Type : MySQL
Source Server Version : 50726
Source Host : localhost:3306
Source Schema : redistest
Target Server Type : MySQL
Target Server Version : 50726
File Encoding : 65001
Date: 29/05/2020 14:55:19
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for ih_goods
-- ----------------------------
DROP TABLE IF EXISTS `ih_goods`;
CREATE TABLE `ih_goods` (
`goods_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`cat_id` int(11) NOT NULL,
`goods_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`goods_id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `ih_goods` VALUES ('1', '0', '小米手机');
-- ----------------------------
-- Table structure for ih_log
-- ----------------------------
DROP TABLE IF EXISTS `ih_log`;
CREATE TABLE `ih_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`event` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`type` tinyint(4) NOT NULL DEFAULT 0,
`addtime` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 16894 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ih_order
-- ----------------------------
DROP TABLE IF EXISTS `ih_order`;
CREATE TABLE `ih_order` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`order_sn` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(11) NOT NULL,
`status` tinyint(1) UNSIGNED NOT NULL DEFAULT 0,
`goods_id` int(11) NOT NULL,
`sku_id` int(11) UNSIGNED DEFAULT NULL,
`price` decimal(10, 2) DEFAULT NULL,
`addtime` int(11) UNSIGNED DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 2369 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ih_store
-- ----------------------------
DROP TABLE IF EXISTS `ih_store`;
CREATE TABLE `ih_store` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`goods_id` int(11) NOT NULL,
`sku_id` int(10) UNSIGNED NOT NULL DEFAULT 0,
`number` int(10) UNSIGNED NOT NULL DEFAULT 0,
`freez` int(11) NOT NULL DEFAULT 0 COMMENT '虚拟库存',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '库存' ROW_FORMAT = Dynamic;
INSERT INTO `ih_store` VALUES ('1', '1', '11', '1000', '0');
-- ----------------------------
-- Table structure for ih_test
-- ----------------------------
DROP TABLE IF EXISTS `ih_test`;
CREATE TABLE `ih_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
INSERT INTO `ih_test` VALUES ('1', '张三');
INSERT INTO `ih_test` VALUES ('2', '王五');
将上面的sql语句导入或者选择redistest数据库选择视图->新建视图,把sql语句放上去再点预览进行导入
先把application/config.php配置的调试打开
‘app_debug’的false改成true
然后配置数据库连接
正确配置 application/database.php里面mysql的账号密码和数据库名字
namespace app\index\controller;
use think\cache\driver\Redis;
use think\Db;
class Index {
public function rudui(){
$store=1000;
$redis=new \Redis();
$redis->connect('127.0.0.1', 6379);
$res=$redis->llen('goods_store');
$count=$store-$res;
for($i=0;$i
$redis->lpush('goods_store',1);
}
}
public function buy () {
//下单前判断redis队列库存量
$redis=new \Redis();
$redis->connect('127.0.0.1',6379);
$count=$redis->lpop('goods_store');
if(!$count){
$this->insertLog('error:no store redis');
return;
}
$price=10;
$user_id=1;
$goods_id=1;
$sku_id=11;
//生成订单
$order_sn=$this->build_order_no();
Db::table('ih_order') ->data(['order_sn'=>$order_sn,'user_id'=>$user_id,'goods_id'=>$goods_id,'sku_id'=>$sku_id,'price'=>$price,'addtime'=>time()])->insert();
$status = Db::table('ih_store')->where('sku_id', $sku_id)->setDec('number');
if($status > 0){
echo "库存减少成功";
$this->insertLog('库存减少成功');
}else{
echo "库存减少成功";
$this->insertLog('库存减少失败');
}
}
//生成唯一订单号
public function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//记录日志
public function insertLog($event,$type=0){
Db::table('ih_log') ->data(['event'=>$event,'type'=>$type]) ->insert();
}
}
注意:先执行一下rudui方法 进行入列,这个后面整合的话可以初始化这个方法,因为这个入列只需要一次就好 博主这里就分开两个方法进行演示,小伙伴们可以自行进行整合优化
用apache自带的ab压力测试工具进行测试
这里模拟一万个请求5000个并发
ab -n 1000 -c http://www.redis233.com/index.php?s=/index/index/buy
1
2
可以看到是成功了!
上述只是简单模拟高并发下的抢购,真实场景要比这复杂很多,很多注意的地方如抢购页面做成静态的,通过ajax调用接口,再如上面的会导致一个用户抢多个,思路:需要一个排队队列和抢购结果队列及库存队列。高并发情况,先将用户进入排队队列,用一个线程循环处理从排队队列取出一个用户,判断用户是否已在抢购结果队列,如果在,则已抢购,否则未抢购,库存减1,写数据库,将用户入结果队列。
Linux系统的小伙伴可参考这个教程
Linux系统秒杀教程
资料代码下载 demo下载
参考链接
nginx环境下TP5隐藏index.php
PHP和Redis实现在高并发下的抢购及秒杀功能示例详解
高并发下,php与redis实现的抢购、秒杀功能