ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

laravel redis秒杀功能

2022-05-19 16:35:21  阅读:182  来源: 互联网

标签:laravel goods return redis 秒杀 user id store resutl


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

搜索

复制

标签:laravel,goods,return,redis,秒杀,user,id,store,resutl
来源: https://www.cnblogs.com/lh460795/p/16289007.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有