学习笔记

Study notes

laravel 礼品码高并发多种实现方法

云逐梦22652019-05-14 14:39:00返回列表

礼品码在高并发下的多种实现方法,结合laravel框架的实现。

高并发实现礼品码抢购功能方法如下:


        一、通过update更新语句会把并发串行化功能实现,通过了压力测试的高并发处理

        (假如这N个用户同时到达update这里,这个时候update更新语句会把并发串行化,也就是给同时到达这里的是N个用户排个序,一个一个执行,并生成排他锁)


        二、laravel+Redis简单实现队列通过了压力测试的高并发处理

            1.先用redis将1000个礼品码缓存

            2.然后用redis setnx判断用户key是否已经存在,存在则返回该用户已经参加了,否则继续

            3.判断礼品码个数,礼品码没有超出预设

            4.更新该礼品码数据用户uid和status状态


不多说,直接上代码:


<?php

namespace App\Http\Controllers;

use App\Giftcode;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use PHPUnit\Framework\Exception;

class GiftcodeController extends Controller
{

    /**
     * yun1121.com:方法一:
     * http://www.xxx.com/api/show1/2
     *
     * 通过update完成高并发更新
     * (假如这N个用户同时到达update这里,这个时候update更新语句会把并发串行化,也就是给同时到达这里的是N个用户排个序,一个一个执行,并生成排他锁)
     *
     * id为主键  更改主键id为一个唯一的键值,更新时如果主键重复则用try catch 将错误catch 最后返回给用户礼品码
     *
     * ab高并发压力测试语句如下:
     * ab -n 100  -c 100 -p 'post.txt' -T 'application/x-www-form-urlencoded' 'http://www.xxx.com/api/show1/27'
     *
     * @param $uid
     * @return \Illuminate\Database\Eloquent\Model|null|object|string|static
     */
    public function show1($uid)
    {
        try{

            $row = DB::update("Update giftcodes set id=:id,status=1,uid=:uid where status=0 and uid is null limit 1 ",['id'=>$uid+10000,'uid'=>$uid]);
            Log::info('uid:', ['msg'=>'抢购','uid'=>$uid]);

        }catch (\Exception $e){

            $row = 0;
            Log::info('uid:', ['msg'=>'抢购失败','uid'=>$uid]);

        }

        if($row){

            $gc_data =  DB::table('giftcodes')->where(['id'=> $uid+10000])->first();
            $gc_data =  (array)$gc_data;
            return $gc_data['gift_code'];

        }else{

            return 'fail';

        }
    }

    /**
     * yun1121.com:方法二:
     * http://www.xxx.com/api/show2/2
     *
     * 1.先用redis将1000个礼品码缓存
     * 2.然后用redis setnx判断用户key是否已经存在,存在则返回该用户已经参加了,否则继续
     * 3.判断礼品码个数,礼品码没有超出预设
     * 4.更新该礼品码数据用户uid和status状态
     *
     * ab高并发压力测试语句如下:
     * ab -n 100  -c 100 -p 'post.txt' -T 'application/x-www-form-urlencoded' 'http://www.xxx.com/api/show2/27'
     *
     * @param $uid
     * @return string
     */
    public function show2($uid)
    {

        $isqueue = Redis::setnx('userqueue_'.$uid,$uid);
        if(!$isqueue){

            Log::info('uid:', ['msg'=>'您已抢购','uid'=>$uid]);
            return '您已抢购';

        }

        Log::info('uid:', ['uid'=>$uid]);
        $giftcode = Redis::rpop('giftcodeslist');

        if(!$giftcode){

            Log::info('uid:', ['msg'=>'已经购空','uid'=>$uid]);
            return '已经购空';

        }

        try{
            $row = DB::table('giftcodes')
                ->where('gift_code',"{$giftcode}")
                ->update(['uid'=>$uid,'status'=> 1]);

            if($row){

                Log::info('uid:', ['msg'=>'抢购成功','uid'=>$uid,'giftcode'=>$giftcode]);
                return $giftcode;

            }else{

                Redis::del('userqueue_'.$uid);
                Redis::lpush('giftcodeslist',$giftcode);
                return 'update fail';

            }

        }catch (\Exception $e){

            Redis::del('userqueue_'.$uid,1);
            Log::info('uid:', ['msg'=>'抢购失败','uid'=>$uid]);
            Redis::lpush('giftcodeslist',$giftcode);
            return 'fail';

        }

    }


    /**
     * yun1121.com:将礼品码预设到缓存中
     * @return string
     */
    public function giftcodeQueue()
    {
        Redis::del('giftcodeslist');
        $giftcode_list = DB::table('giftcodes')->where(['status'=> 0])->get()->toArray();

        if($giftcode_list){

            foreach ($giftcode_list as $key=>$val){

                $val = (array)$val;
                Redis::lpush('giftcodeslist',$val['gift_code']);

            }

        }

        return '目前码数:'.Redis::llen('giftcodeslist');
    }
}

        以上代码通过高并发测试成功!

ab -n 100  -c 100 -p 'post.txt' -T 'application/x-www-form-urlencoded' 'http://www.xxx.com/api/show1/27'

        

        欢迎大家讨论提供更多的实现方法!

        尊重原创,转载请注明来源 http://www.yun1121.com/study/view/id/175 云逐梦

返回
顶部