• 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

  • 相关阅读:
    linux 常用操作指令(随时更新)
    Spring @Scheduled应用解析
    H5的FormData对象完成ajax上传文件multiFile
    微服务的4个设计原则和19个解决方案
    微服务实战(六):如何做好服务拆分?
    微服务实战(五):微服务化之缓存的设计
    微服务实战(四):微服务化之无状态化与容器化
    微服务实战(三):以MySQL为例,从原理上理解那些所谓的数据库军规
    微服务实战(二):微服务的接入层设计与动静资源隔离
    微服务实战(一):微服务化的基石——持续集成
  • 原文地址:https://www.cnblogs.com/lh460795/p/16289007.html
Copyright © 2020-2023  润新知