概述
第一种方式
$db = MySQLDB::getInstance();
$info = $db->fetchRow('select * from goods where goods_id=1');
//判断是否还有库存
if ($info['stock'] <= 0) {
exit('卖完了');
}
//减少库存,num 只是一个记录修改数据的次数,可以判断是否存在超卖现象
$result = $db->update("update goods set stock=stock-1,num=num+1 where goods_id=1 and stock>0");
if (!$result) {
exit('抢购失败');
}
file_put_contents('./order.txt', $result . PHP_EOL, FILE_APPEND);
exit('抢购成功');
通过apache压测工具ab来试一试会不会超卖
数据库情况

ab -c 100 -n 1000 http://test.localhost.com/database.php
结果
数据库情况

日志文件

没有超卖
这种方案适合用户量少的情况,mysql压力不会太大
第二种方案
监听key + 事务 实现
具体代码
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 5);
//监听已抢购的数量,如果在事务执行之前这个 key 被其他命令所改动,那么事务将被打断。
$redis->watch('rush:goods_stock:1');
//获取库存
$stock = $redis->get('rush:goods_stock:1');
if ($stock == 0) {
die('抢购失败,已经销售完毕');
}
//事务开始
$redis->multi();
//库存 -1
$redis->decr('rush:goods_stock:1');
//执行提交
$res = $redis->exec();
//事务提交成功
if ($res) {
$data = [
'goods_id'=>1,
'user_id'=>rand(1,9999),
'time'=>microtime(true)
];
$redis->lPush('rush:goods:1',json_encode($data));
file_put_contents('./order.txt', 1 . PHP_EOL, FILE_APPEND);
die('抢购成功');
}
die('抢购失败');
设置redis 的值

通过ab压测
ab -c 100 -n 1000 http://192.168.1.13:82/redis.php
查看redis数据情况

这种方案不一定是先提交的先下单,可能会涉及到还有库存抢购失败的情况。
第三种方案
通过把库存设置为redis 队列 来实现
先设置商品库存的队列
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 5);
//库存
$stock = 10;
//先清空
$redis->del('rush:goods_stock:queue:2');
//放入队列中
for ($i = 0; $i < $stock; $i++) {
$redis->lPush('rush:goods_stock:queue:2', 1);
}
die('放入队列完成');
执行完成看一下redis数据

实现抢购功能
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 5);
//读取队列,redis操作都是原子性的,不用担心会重复读取
if ($redis->rPop('rush:goods_stock:queue:2')) {
$data = [
'goods_id'=>2,
'user_id'=>rand(1,9999),
'time'=>microtime(true)
];
$redis->lPush('rush:goods:2',json_encode($data));
die('抢购成功');
}
die('抢购失败,已经销售完毕');
压测
ab -c 100 -n 1000 http://192.168.1.13:82/redis.php
结果数据正确

该方案用户基本可以先下手为强。注意设置库存的地方
库存解决好了后面就是把订单写入数据库,其实跑一个脚本去读抢购成功的队列就行了
有的文章是直接判断抢购成功的队列是否小于库存,并且写入队列的时候没有减少库存。这样的方式必须等待抢购完毕之后才能写入数据库,因为一边进一边出,会导致超卖,这种方式不太灵活。也看具体场景吧!
最后
以上就是默默乌冬面为你收集整理的php redis decr_PHP 通过redis和mysql实现秒杀业务的全部内容,希望文章能够帮你解决php redis decr_PHP 通过redis和mysql实现秒杀业务所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复