微信小程序结合 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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现