PHP+Redis实现简单的秒杀功能

秒杀一般会在短时间内对接口有大量的请求,并发量比较大,如果直接对数据库进行操作,会影响系统的稳定,而使用redis就可以尽量避免这个情况了。

下边用redis模拟了用户抢购的场景

<?php
// 连接Redis
$redis = new Redis();
$redis->connect('127.0.0.1');
// 模拟用户抢购,其中存在同一个用户多次点击
$userIds1 = range(1, 10);
$userIds2 = range(5, 15);
$userIds = array_merge($userIds1, $userIds2);
// 设置商品信息
$goodsId = 1;
$goodsStock = 5;
// 商品库存存储名称
$stockKey = 'goods_stock_' . $goodsId;
$redis->set($stockKey, $goodsStock);
// 设置锁避免并发
$lockKey = 'lock_' . $goodsId;
$time = time();
foreach ($userIds as $v){
    // 设置商品每个用户只能抢一件
    $userKey = 'user_' . $goodsId . '_' . $v;
    // 判断用户是否已抢购
    $user = $redis->get($userKey);
    if ($user){
        echo '用户【' . $v . '】该商品限购一件';
        echo '<br/>';
        continue;
    }
    $lock = $redis->setnx($lockKey, 1);
    if ($lock){
        // 设置过期时间
        $redis->expire($lockKey, 2);
        // 预减库存
        $stock = $redis->decrBy($stockKey, 1);
        if ($stock >= 0){
            // 抢购成功则设置用户信息
            $redis->set($userKey, $userKey);
            $order_no = date("YmdHis") . rand(10000, 99999);
            $data = [
                'order_no' => $order_no,
                'goods_id' => $goodsId,
                'user_id' => $v,
                'create_time' => $time
            ];
            $redis->lPush('orders', json_encode($data));
            echo '用户【' . $v . '】抢购成功,订单号【' . $order_no . '】';
        }else{
            $redis->incrBy($stockKey, 1);
            echo '用户【' . $v . '】库存不足';
        }
    }else{
        $redis->del($lockKey);
        echo '用户【' . $v . '】系统繁忙';
    }
    echo '<br/>';
}

代码执行的结果如下

可以看到是不会出现超卖的情况,这里释放锁也可以放到抢购成功之后。当订单信息入列后可以在另一边执行出列,再把订单信息插入数据库。

// 连接Redis
$redis = new Redis();
$redis->connect('127.0.0.1');
// 移除并返回列表key的尾元素
$orderInfo = $redis->rPop('orders');
// 存在订单则加入数据库
if ($orderInfo){
    // 模拟加入数据库
    $fp = fopen('order.txt',"a");
    fwrite($fp,date("Y-m-d H:i:s") . ':' . var_export($orderInfo,true)."\r\n");
    fclose($fp);
}
echo $orderInfo;

以上操作就能实现一个简单的秒杀流程了,更具体的操作则可以根据项目需求不同而做出更改,

还可以使用队列方式实现秒杀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火³可²

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值