微信小程序结合 tp实现秒杀(库存预热)

一:建表

1:用户表

2:订单表

 3:收货地址

 

 4:秒杀的商品表:

二:库存预热:

模型代码 :

控制器代码:

 

 

 

 我们要定时预热:

博客链接:

复制代码
 public function start()
    {
        $last = time();
        $task = [6 => $last, 10 => $last, 30 => $last, 60 => $last, 180 => $last, 300 => $last];

        $this->timer = \Workerman\Lib\Timer::add($this->interval, function () use (&$task) {
            //每隔60秒执行一次
            try {
                //执行库存预热
               $this->stockPreheat();

                $now = time();
                foreach ($task as $sec => $time) {
                    if ($now - $time >= $sec) {
                        //每隔$sec秒执行一次
                        $task[$sec] = $now;
                    }
                }
            } catch (\Throwable $e) {
            }
        });
    }


    /**
     * 库存预热
     */
    public function stockPreheat()
    {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);

        //去查询距离秒杀活动开始时间小于5分钟的数据进行预热
        $preheatData = SeckillGoods::getPreheatGoods();
        //进行把待预热的商品添加到本地数据库中,添加到redis中
        foreach ($preheatData as $val) {
            //把每个要预热的商品数据追加到本地redis数据库
            //秒杀商品库存队列 具有唯一性
            $seckillQueueKey = 'seckill_queue_' . $val['id'];
            //如果秒杀商品库存大于0则进行追加队列
            if ($val['stock_number'] > 0) {
                for ($i = 0; $i < $val['stock_number']; $i++) {
                    $redis->rPush($seckillQueueKey,1);
                }
                //修改预热 状态
                SeckillGoods::where('id',$val['id'])
                    ->update(['is_preheat'=>1]);
            }
        }

        return successJson(0,'预热库存成功');
    }
复制代码

这里可以写入日记(参考以下代码)

复制代码
  public function start()
    {
        $last = time();
        $task = [6 => $last, 10 => $last, 30 => $last, 60 => $last, 180 => $last, 300 => $last];

        $this->timer = \Workerman\Lib\Timer::add($this->interval, function () use (&$task) {
            //每隔2秒执行一次
            //进行调用库存归还代码
            file_put_contents('1.txt','123');
            try {
                $now = time();
                foreach ($task as $sec => $time) {
                    if ($now - $time >= $sec) {
                        //每隔$sec秒执行一次
                        $task[$sec] = $now;
                    }
                }
            } catch (\Throwable $e) {
                //失败记录日志
                file_put_contents('error.txt',$e->getMessage());
            }
        });
    }
复制代码

 三: 后台接口

复制代码
 1     /**
 2      * 秒杀接口
 3      */
 4     public function seckill(Request $request)
 5     {
 6         //1.接收秒杀商品参数(参数验证),未登录用户不能参与秒杀
 7         $params = $request->post();
 8         $userID = $request->user_id;
 9 
10         //2.查询本地还有没有库存,如果没有库存,则提示库存不足
11         $redis = Redis::getInstance();
12         //求出秒杀队列的长度
13         $listName = 'seckill_queue_' . $params['goods_id'];
14         $listLen = $redis->lLen($listName);
15         //如果队列的长度小于等于0,没有库存
16         if ($listLen <= 0) {
17             return failJson('6000', '您手慢了,商品被抢购空了');
18         }
19         //3.如果有库存,进行判断该用户是否已经参与过秒杀,秒杀成功的用户数据存储到哪里的(set集合里的,无序且唯一)
20         $setName = 'seckkill_success_member_' . $params['goods_id'];
21         $bool = $redis->sIsMember($setName, $userID);
22         if ($bool) {
23             return failJson('6001', '您已经秒杀过了,请不要在参与了');
24         }
25         //把秒杀成功的用户id放到集合里
26         $redis->sAdd($setName, $userID);
27         //4.如果set集合里没有该用户的信息,进行减本地库存,然后生成订单
28         $redis->lpop($listName);
29         // 启动事务
30         Db::startTrans();
31         try {
32             //订单数组
33             //去查询秒杀商品的价格
34             $goods = SeckillGoods::getSeckillGoodsDetailByID($params['goods_id']);
35             $orderArr = [
36                 'user_id' => $userID,
37                 'goods_id' => $params['goods_id'],
38                 'goods_nums' => $params['goods_nums'],
39                 'order_no' => makeOrderSn(),//唯一的订单号
40                 'status' => OrderEnum::$paidStatus,
41                 'total_price' => ($goods->sckill_price * 100 * $params['goods_nums']) / 100//商品的价格需要重新计算
42             ];
43             $res = Order::createOrder($orderArr);
44             //5.分布式的数据库,如果以主键id作为key查询数据库,就有可能有问题
45             if ($res) {
46                 // 提交事务
47                 Db::commit();
48             }
49             //6.返回下单成功与否的状态
50             return successJson(0, '下单成功', $res);
51         } catch (\Exception $exception) {
52             // 回滚事务
53             Db::rollback();
54             throw new Exception($exception->getMessage());
55         }
56     }
复制代码

 

posted @   王越666  阅读(540)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示