高并发实现礼品码抢购功能方法如下:
一、通过update更新语句会把并发串行化功能实现,通过了压力测试的高并发处理
(假如这N个用户同时到达update这里,这个时候update更新语句会把并发串行化,也就是给同时到达这里的是N个用户排个序,一个一个执行,并生成排他锁)
二、laravel+Redis简单实现队列通过了压力测试的高并发处理
1.先用redis将1000个礼品码缓存
2.然后用redis setnx判断用户key是否已经存在,存在则返回该用户已经参加了,否则继续
3.判断礼品码个数,礼品码没有超出预设
4.更新该礼品码数据用户uid和status状态
不多说,直接上代码:
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 云逐梦
网友评论