概述
先普及一下,什么叫超卖,订单商品数据量大于商品库存数量,就叫做超卖;
那么问题来了,为什么会超卖呢?
在商城抢购中,假如库存为100个,这时有100 000个并发请求过来了,最后库存只剩1个时,假如还有1000个并发请求,如果这1000个请求都成功了,那最后库存是不是变成了-999,这就是超卖。(以上仅为理论上理解超卖)
先介绍一个很有用的工具,并发测试工具ab.exe,在Apache的bin目录下打开cmd窗口,输入命令ab -n10000 -c1000 http://localhost/code/mysql.php,表示测试10000个请求,并发量为1000,测试访问地址为http://localhost/code/mysql.php
先建一个商品表,store为库存,以下为一些用到SQL语句
// 建表
create table product(
id int(8) not null auto_increment comment '产品id',
name varchar(25) not null default '' comment '产品名',
price decimal(10,3) not null default 0 comment '价格',
store int(8) not null default 0 comment '库存',
primary key(id)
)engine=innodb default charset=utf8;
// 添加数据
insert into product value(1, '小米手环', 198, 10);
// 查看表数据
select * from product;
// 设置库存
update product set store=10 where id=1;
接下来,用代码解释下高并发抢购的超卖,直接在MySQL上测试,以下就是mysql.php文件
<?php
header("content-type:text/html; charset=utf-8");
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'root') or die("数据库连接失败");
$pdo->exec("set names utf8");
$sql = "select * from product where id=1";
$res = $pdo->query($sql);
$data = $res->fetch(PDO::FETCH_ASSOC);
// print_r($data);
if($data['store']>0){
// 开启事务
$pdo->beginTransaction();
$sql = "update product set store=store-1 where id=1";
$res = $pdo->query($sql);
print_r($res);
if($res){
echo "抢到啦!";
}else{
echo "抢购失败...";
$pdo->rollBack();
}
$pdo->commit();
}else{
echo '商品已被抢购一空,感谢参与!';
}
?>
给它10000个请求,并发为1000
来看下商品表中的库存store
再来看下用redis实现的,用到了redis的事务、乐观锁,以下为redis.php
<?PHP
header("content-type:text/html; charset=utf-8");
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'root') or die("数据库连接失败");
$pdo->exec("set names utf8");
$redis = new Redis();
$redis->connect("localhost");
$redis->watch('salec'); // 虚拟销量
$salec = $redis->get('salec');
$store = 10; // 设置虚拟库存与数据库的一致
if($salec >= $store){
exit("商品已被抢购一空,感谢参与!");
}
// 开启事务
$redis->multi();
$redis->incr('salec'); // 增加销量
$res = $redis->exec(); // 执行事务 如果发现自己拿到的key被修改了,事务则被打断
if($res){
// 以下代码只是为了测试,实际中是交给 MQ 去处理
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'root') or die("数据库连接失败");
$pdo->exec("set names utf8");
$sql = "update product set store=store-1 where id=1";
if($pdo->query($sql)){
echo "抢到啦!";
}
}else{
echo "抢购失败...";
}
?>
也给它10000个请求,并发为1000
看下商品表中的库存store
redis完美解决了高并发抢购的超卖现象。
最后
以上就是美好保温杯为你收集整理的redis实战-高并发抢购案例的全部内容,希望文章能够帮你解决redis实战-高并发抢购案例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复