redis实战-高并发抢购案例

先普及一下,什么叫超卖,订单商品数据量大于商品库存数量,就叫做超卖;

那么问题来了,为什么会超卖呢?

在商城抢购中,假如库存为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完美解决了高并发抢购的超卖现象。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值