秒杀是一个非常考验性能的业务场景
如果按照我们日常逻辑实现,总会出现超卖的现象。
那么如何保证系统的稳定性和数据的正确性。
一、日常下单扣库存模式:
以下代码是一遍情况下的下单逻辑:
<?php
$error_level = error_reporting(0);
$con = new mysqli('localhost','root','root','test');
if(!$con){
echo "数据库连接失败";
}
$sql = "select * from products where id=1";
$result = mysqli_query($con,$sql);
$aa= mysqli_fetch_row($result);
if($aa[3]>0){
sleep(1);
$sql = "update products set store=store-1 where id=1";
if(mysqli_query($con,$sql)){
echo "更新成功";
}
}else{
echo "没有库存";
}
这里使用 ab压测去执行,会发现库存都会成为负数。
二、通过redis去实现秒杀的业务前置拦截。
我们这里主要考虑秒杀抢购前先扣库存,如果库存足够再走下单流程,如果不够直接结束活动
我们这里是有redis的事务去处理具体如下:
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$store = 10; // 当前商品秒杀的库存数, 设置->存储本地,不能读库
// 监视销量 虚拟库存
$redis->watch('sales'); // 监视作用,key不存在 默认创建为0
$salse = $redis->get('sales'); //获取销量
var_dump($salse);
// 当秒杀结束后要开始另一个秒杀活动时将sales 置空,不然销量依然是10
// $redis->del('sales');
// exit();
if ($salse>=$store) {
exit("秒杀已经结束!");
}
// 开启事务处理
$redis->multi();
$redis->incr('sales');//增加销量
$res = $redis->exec();//提交事务 成功 1 失败 0
if($res){
// 提交成 开始更改库存 下订单
include "db.php";
$sql = "update products set store = store -1 where id =1";
if ($mod->query($sql)) {
echo "库存更新成功!";
}
}else{
//事务提交失败不减库存
exit("失败");
}
这里使用 ab压测去执行,会发现库存都一直会为0。
这里需要注意的是“sales”在一场秒杀活动结束之后一定要置空,不然会一直秒杀结束。
转载请注明:夜阑小雨 » php+redis秒杀实现