一、中奖率,先在后台设定好奖项名称,抽奖份数,以及中奖百分比
奖品表draw

二、 借助文件排他锁,在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户"服务器繁忙"
阻塞(等待)模式,一般都是用这个模式,排队式抽奖,一个人抽完再到下一位
<?php
$fp = fopen("lock.txt", "w+");
if(flock($fp,LOCK_EX))
{
//..处理订单
flock($fp,LOCK_UN);
}
fclose($fp);
?>
非阻塞模式
<?php
$fp = fopen("lock.txt", "w+");
if(flock($fp,LOCK_EX | LOCK_NB))
{
//..处理订单
flock($fp,LOCK_UN);
}
else
{
echo "系统繁忙,请稍后再试";
}
fclose($fp);
?>
完整php代码 ,文件锁进行防高并发(在目录下添加一个lock.txt),通过百分比计算出抽奖率,随机抽取一份奖品
public function draw(){
//文件锁进行防高并发
$fp = fopen("lock.txt", "w+");
if(flock($fp,LOCK_EX))
{
$token = $this->request->param('token');
$res['code'] = 500;
if($token) {
$userData = DmhdUserModel::where('token', $token)->find();
if ($userData) {
$create['userId'] = $userData['id'];
$list = DmhdDrawModel::where('percent','>',0)->where('status',0)->select();
$probabilities = [];
//通过百分比计算出抽奖率,随机抽取一份奖品
foreach($list as $k=>$vo){
$probabilities[$vo['name']] = $vo['percent'];
}
// 计算总概率
$proSum = array_sum(array_column($list, 'percent'));
// 概率数组循环
foreach ($probabilities as $key => $proCur) {
$randNum = mt_rand(1, $proSum); // 生成随机数
if ($randNum <= $proCur) {
$result = $key; // 中奖奖品编号,奖品名称
$res['code'] = 200;
$res['drawName'] = $result;
//1、抽奖次数
DmhdDrawModel::where('name',$result)->setInc('drawCount');
//判断奖品的抽奖次数是否大于等于可抽次数
$drawData = DmhdDrawModel::where('name',$result)->find();
if($drawData['drawCount']>=$drawData['count']){
DmhdDrawModel::where('name',$result)->update(['status'=>1]);
}
//2、用户抽中的奖品名称
DmhdUserModel::where('token', $token)->update(['drawName'=>$result,'status'=>1]);
flock($fp,LOCK_UN);
fclose($fp);
return json($res);
} else {
$proSum -= $proCur; // 更新总概率精度
}
}
}
}
flock($fp,LOCK_UN);
fclose($fp);
return json($res);
}
fclose($fp);
}
本文介绍了如何在PHP中设置抽奖的中奖率,并通过文件排他锁实现防止高并发的问题。奖品信息存储在draw表中,采用文件锁(flock)确保抽奖过程的顺序,避免并发导致的错误。代码示例展示了阻塞和非阻塞模式下的抽奖逻辑。
484

被折叠的 条评论
为什么被折叠?



