php+redis一步一步测试秒杀
1、普通的秒杀查库减库存:
<?php
/**
100个用户同时访问100次会出现超卖
**/
//连接数据库
$dsn = "mysql:host=localhost;dbname=ceshi";
$db = new PDO($dsn, 'root', 'root');
//价格
$price=10;
//用户id
$user_id=1;
//商品id
$goods_id=1;
//skuid
$sku_id=11;
//数量
$number=1;
//生成唯一订单
function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//库存是否大于0
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
$row=$db->query($sql)->fetch();
if($row['number']>0){//高并发下会导致超卖
$order_sn=build_order_no();
//生成订单
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
$order_rs=$db->exec($sql);
//库存减少
$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
$store_rs=$db->exec($sql);
if($store_rs){
echo "库存减少成功";
}else{
echo "库存减少失败";
}
}else{
echo "库存不够";
}
?>
2、把数据库的库存字段设置为无符号:
<?php
/**
100个用户同时访问600次的情况下会出现超卖
**/
//连接数据库
$dsn = "mysql:host=localhost;dbname=ceshi";
$db = new PDO($dsn, 'root', 'root');
//价格
$price=10;
//用户id
$user_id=1;
//商品id
$goods_id=1;
//skuid
$sku_id=11;
//数量
$number=1;
//生成唯一订单
function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//库存是否大于0
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";
$row=$db->query($sql)->fetch();
if($row['number']>0){//高并发下会导致超卖
$order_sn=build_order_no();
//生成订单
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
$order_rs=$db->exec($sql); //库存减少
$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
$store_rs=$db->exec($sql);
if($store_rs){
echo "库存减少成功";
}else{
echo "库存减少失败";
}
}else{
echo "库存不够";
}
?>
3、采用排它锁解决:
<?php
/**
100个用户同时访问1500次的情况下会出现超卖
**/
//连接数据库
$dsn = "mysql:host=localhost;dbname=ceshi";
$db = new PDO($dsn, 'root', 'root');
//价格
$price=10;
//用户id
$user_id=1;
//商品id
$goods_id=1;
//skuid
$sku_id=11;
//数量
$number=1;
//生成唯一订单
function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//库存是否大于0
$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";
$row=$db->query($sql)->fetch();
if($row['number']>0){//高并发下会导致超卖
$order_sn=build_order_no();
//生成订单
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
$order_rs=$db->exec($sql);
//库存减少
$db->beginTransaction();//开启事务处理
$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
$store_rs=$db->exec($sql);
if($store_rs){
echo "库存减少成功";
$db->commit();
}else{
echo "库存减少失败";
}
}else{
$db->rollBack();
echo "库存不够";
}
?>
4、采用redis队列实现
第一步把库存存入队列中
<?php
//500个库存存入redis队列
$store=20;
$redis=new Redis();
$result=$redis->connect('127.0.0.1',6379);
$res=$redis->llen('goods_store');
$count=$store-$res;
for($i=0;$i<$count;$i++){
$redis->lpush('goods_store',1);
}
echo $redis->llen('goods_store');
?>
队列操作:
<?php
/**
可以抗住任何并发
**/
//连接数据库
$dsn = "mysql:host=localhost;dbname=ceshi";
$db = new PDO($dsn, 'root', 'root');
//价格
$price=10;
//用户id
$user_id=1;
//商品id
$goods_id=1;
//skuid
$sku_id=11;
//数量
$number=1; //生成唯一订单
function build_order_no(){
return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//连接redis
$redis=new Redis();
$result=$redis->connect('127.0.0.1',6379);
// echo $redis->llen('goods_store');
// die;
$count=$redis->lpop('goods_store');
if(!$count){
echo "redis队列无库存";
return false; }
//生成订单
$order_sn=build_order_no();
$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price)
values('$order_sn','$user_id','$goods_id','$sku_id','$price')";
$order_rs=$db->exec($sql); //库存减少
$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";
$store_rs=$db->exec($sql);
if($store_rs){
echo "库存减少成功";
}else{
echo "库存减少失败";
}
?>
ab测试:
ab -n 2000 -c 100 http://localhost/miaosha/index2.php
数据库导入
-- ----------------------------
-- 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) NOT NULL,
PRIMARY KEY (`goods_id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of ih_goods
-- ----------------------------
INSERT INTO `ih_goods` VALUES ('1', '0', '小米手机'); -- ----------------------------
-- Table structure for `ih_order`
-- ----------------------------
DROP TABLE IF EXISTS `ih_order`;
CREATE TABLE `ih_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_sn` char(32) NOT NULL,
`user_id` int(11) NOT NULL,
`status` int(11) NOT NULL DEFAULT '0',
`goods_id` int(11) NOT NULL DEFAULT '0',
`sku_id` int(11) NOT NULL DEFAULT '0',
`price` float NOT NULL,
`addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COMMENT='订单表'; -- ----------------------------
-- 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`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='库存'; -- ----------------------------
-- Records of ih_store
-- ----------------------------
INSERT INTO `ih_store` VALUES ('1', '1', '11', '20', '0');
php+redis一步一步测试秒杀的更多相关文章
- Android 从硬件到应用程序:一步一步爬上去 6 -- 我写的APP测试框架层硬件服务(终点)
创Android Applicationproject:采用Eclipse的Android插入ADT创Androidproject,project名字Gpio,创建完成后,project文件夹pack ...
- jumpservice一步一步安装
一步一步安装 (CentOS) 本文档旨在帮助用户了解各组件之间的关系, 生产环境部署建议参考 进阶安装文档 云服务器快速部署参考 极速安装 安装过程中遇到问题可参考 安装过程中常见的问题 测试推荐环 ...
- Dubbo入门到精通学习笔记(十五):Redis集群的安装(Redis3+CentOS)、Redis集群的高可用测试(含Jedis客户端的使用)、Redis集群的扩展测试
文章目录 Redis集群的安装(Redis3+CentOS) 参考文档 Redis 集群介绍.特性.规范等(可看提供的参考文档+视频解说) Redis 集群的安装(Redis3.0.3 + CentO ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
我个人认为Actor应该是Dapr里比较重头的部分也是Dapr一直在讲的所谓"stateful applications"真正具体的一个实现(个人认为),上一章讲到有状态服务可能很 ...
- 如何一步一步用DDD设计一个电商网站(五)—— 停下脚步,重新出发
阅读目录 前言 单元测试 纠正错误,重新出发 结语 一.前言 实际编码已经写了2篇了,在这过程中非常感谢有听到观点不同的声音,借着这个契机,今天这篇就把大家提出的建议一个个的过一遍,重新整理,重新出发 ...
- C#编写window服务,一步一步(1)
Window服务是啥,这里就不废话了,如何用在哪里用也不废话了,这里我这篇文章只是详述了我在vs2012中创建window服务的经过,希望对你有所帮助. 另外:我在编写服务过程中参考了 Profess ...
- 12.Linux软件安装 (一步一步学习大数据系列之 Linux)
1.如何上传安装包到服务器 有三种方式: 1.1使用图形化工具,如: filezilla 如何使用FileZilla上传和下载文件 1.2使用 sftp 工具: 在 windows下使用CRT 软件 ...
- 【新手出发】从搭虚拟机开始,一步一步在CentOS上跑起来.Net Core程序
文章背景 微软6月26号发布core 1.0版本后,园子里关于这方面的文章就更加火爆了,不管是从文章数量还是大家互动的热情来看,绝对是最热门的技术NO.1.我从去年底开始接触.net core到现在也 ...
- 一步一步学ROP之linux_x86篇
一步一步学ROP之linux_x86篇 作者:蒸米@阿里聚安全 一.序 ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过 ...
随机推荐
- JQuery.BlockUI使用方法举例
JQuery.BlockUI是众多JQuery插件弹出层中的一个,它小巧(原版16k,压缩后10左右),容易使用, 功能齐全,支持Iframe,支持Modal,可定制性高也意味他默认谦虚的外表. jQ ...
- [CareerCup] Single Valid Tree
https://www.careercup.com/question?id=5103530547347456 Given a list of nodes, each with a left child ...
- SQLPrompt 6.3.0.354 完美破解 安装于 SQL Server 2012/2014
SQL SERVER 2012格式化 SQL SERVER 2014格式化 SQLPrompt_6.4.0.641 破解版 百度云下载 迅雷下载 百度网盘下载 SQL Prompt 是一款拥有SQL智 ...
- Object.defineProperty()方法学习笔记
这是js中一个非常重要的方法,ES6中某些方法的实现依赖于它,VUE通过它实现双向绑定 此方法会直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象 参数 Object.def ...
- 到处抄来的SUCTF2019 web wp
0x01 EasySQL 这是一个考察堆叠注入的题目,但是这道题因为作者的过滤不够完全所以存在非预期解 非预期解 直接构造 *,1 这样构造,最后拼接的查询语句就变成了 select *,1||fla ...
- 【计算机视觉】OPENCV对于有alpha通道的透明背景图片的读取和图片叠加
这个是我自己做的粗略的螺旋丸的图,导出为png并带有alpha通道. 最后和一只狗合成成这个样子. 效果还是可以的. 为了实现这个效果,首先我们要明白具有透明通道的图片的OpenCV的读取方式.在Op ...
- 【C/C++开发】关于位域操作
几篇较全面的位域相关的文章: http://www.uplook.cn/blog/9/93362/ C/C++位域(Bit-fields)之我见 C中的位域与大小端问题 内存对齐全攻略–涉及位域的内存 ...
- 【牛客网】Finding Hotel
[牛客网]Finding Hotel 忘记K远点对的剪枝的我有点自闭 事实上我们只要先建一棵KD树出来,维护一下所在的矩形,和子树里的最小值 每次查询的时候如果最小值比查询的值要大的话就退出 当前的答 ...
- Scratch教程:谁是真悟空
在西游记中,有一集是“真假悟空”,六耳猕猴变成了悟空的模样与真悟空真假难辨,打的不可开交. 在Scartch中,我们常常会使用一个本体来生成多个克隆体,这在开发过程中有重要的意义.但在实际操作中,每个 ...
- ASP.NET Core分布式项目-2.oauth密码模式identity server4实现
源码下载 这里根据<ASP.NET Core分布式项目-1.IdentityServer4登录中心>的代码来继续更新oauth密码模式,这里的密码模式比上次的客户端模式更安全 在WebAp ...