laravel redis秒杀功能
1.初始化:
秒杀商品,将商品以list数据类型存入redis(每个数量为一个元素);
2.购买:
1)购买用户入队列,如果用户队列长度超过指定的排队长度,则返回排队数过多
2)如果用户队列长度小于指定的排队长度,然后生成订单,减去库存。下单完成
<?php namespace App\Http\Controllers; use App\Models\Goods; use App\Models\Orders; use App\Services\RedisLock; use Exception; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Redis; class MiaoshaController extends Controller { //排队人数 private $listNumber = 50; /** * 实现秒杀 */ public function secondsKill(Request $request) { try { $user_data = $request->only(['user_id', 'goods_id']); if ( !$user_data ) { return $this->failed('数据不能为空'); } $goodsId = $user_data['goods_id']; $userId = $user_data['user_id']; #访问用户入队接口 $user_list = $this->requestUser($userId); if ( !$user_list ) { return $this->failed('排队数大于商品总数:'.Redis::llen('user_list')); } #消费商品,从队列中取出商品 $count = Redis::lpop('goods_store:' . $goodsId); if(!$count) { return $this->failed('商品抢光了'); } #进入redis锁 $redisLock = new RedisLock($userId); $lock = $redisLock->lock(); if ($lock) { #最后进入数据库操作(每次固定消费1个) $mysql_data = $this->storeOrder($userId, $count, '1'); if ( !$mysql_data ) { $redisLock->unlock(); return $this->failed('生成订单失败'); } else { #关闭锁 $redisLock->unlock(); return $this->success('抢购成功'); } } return $this->success('生成订单失败'); } catch (Exception $e) { throw $e; } } /** * 将商品加入redis */ public function storageGoods(Request $request) { try { #查询商品 $resutl = Goods::where('id', $request->goods_id)->select(['store','id'])->first(); $store = $resutl->store; $res = Redis::llen('goods_store:' . $resutl->id); $count = $store - $res; for($i = 0;$i < $count; $i++){ Redis::lpush('goods_store:' . $resutl->id, $resutl->id); } return $this->success('加入成功'.$count); } catch (Exception $e) { throw $e; } } /** * 将用户也存入队列中(就是将访问请求数据)(此处没有进行用户过滤,同一个用户进行多次请求也会进入队列) */ private function requestUser($userId) { $res = Redis::llen('user_list'); #判断排队数 if ($res = Redis::llen('user_list') > $this->listNumber) { // return '排队数大于商品总数'; return false; } #添加数据 Redis::lpush('user_list', $userId); return true; } /* *下单 */ private function storeOrder($user_id, $goods_id, $number) { try { #开启事务 DB::beginTransaction(); #查询库存sharedLock()共享锁,可以读取到数据,事务未提交不能修改,直到事务提交 #lockForUpdate()不能读取到数据 $resutl = Goods::where(['id'=>$goods_id])->lockForUpdate()->first(); #添加订单 if ( $resutl ) { $resutl_order = Orders::create([ 'user_id' => $user_id, 'goods_id' => $goods_id, 'goods_number' => $number, 'ordersn' => $this->buildOrderNo(), 'price' => $resutl->price, ]); #减少库存 $resutl_update = Goods::where('id',$goods_id)->where('store', '>', 0)->decrement('store'); #将用户从队列里面弹出,允许下一个用户进来 Redis::rpop('user_list'); if ($resutl_order->id > 0 && $resutl_update > 0) { DB::commit(); return true; } } DB::rollBack(); return false; } catch(Exception $e) { throw $e; } } /** * 生成唯一订单号 */ private function buildOrderNo(){ return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); } }
转载:https://blog.csdn.net/xiayu204575/article/details/106719845