• php实现题目抢答、商品秒杀等类型的需求


    最近和其他部门合作项目,当然我是负责php接口方面的工作,
    get到一些东西,所以来分享记录一下。

    项目需求:

    题目将通过主持人ipad投射至大屏幕,选手按‘抢答’
    按钮进行抢答。抢答成功,选手所在组,以及大屏幕上广播抢答成功者的ipad屏幕,
    抢答失败选手,返回抢答失败界面。

    需求分析:

    这里抢答,其实就是和秒杀活动机制一样了,不过这里场景可能稍微复杂点,
    需要用到强弱连接,实时广播,大家可以去看看GatewayWordker当然,今天我们只是单纯
    讨论抢答机制是如何实现。那么既然抢答,就要考虑高并发问题了。

    思路分析:

    1.把题目的状态写在redis里面,比如题目还没有被抢状态为1,抢完状态为0
    2.选手进行抢答时,查询redis状态,为0,直接返回,题目已经被抢完;
    3.选手进行抢答时,查询redis状态,为1,进入下一步逻辑操作,修改redis状态为0,
    进入数据库查询改题目数据,运用行级琐机制。返回逻辑处理结果

    框架依然用的是laravel,开发模式用的是仓库模式,这用有利于项目后期的维护和升级。

    (数据字段涉及安全,暂时用test1等表示便好)

    /******首先进行题目获取,并把题目对应的redis编号改为1******/

     1     /**
     2      * @desc    随机获得抢答题题目
     3      * @date    2017/4/19 17:26
     4      * @param   [type]
     5      * @author  十月桂花香十里
     6      * @return  [bool or array]
     7      */
     8     public function getQuickQuestion(){
     9         //获取抢答题随机题号id
    10         $randNum = $this->getRandArray(config('test.start_quick_id'),config('test.end_quick_id'),config('djm.max_quick'));
    11         DB::transaction(function () use ($randNum){
    12             //将抢答题题号id写进redis,值为1题目可以进行抢答,0不可以进行抢答(为了便于后期维护,0和1都可以写进配置文件中)
    13             $redis = PRedis::connection('default');
    14             foreach($randNum as $k=>$v){
    15                 $redis->set("check_quick_id_".$v,1);
    16             }
    17             //将数据库中抢答题对应的id记录,test3状态改为可进行抢答
    18             //DjmQuestion::whereIn('id', $randNum)->update(['test3'=>1]);
    19         });
    20         $res = DjmQuestion::whereIn('id', $randNum)
    21          ->orderByRaw(DB::raw("FIELD(id, ".implode(',', $randNum).")"))
    22             ->get(['id','test1','test2','test3','test4']); 23 if($res){
    24       foreach($res as $k=>$v){ 25 $res[$k]['test6'] = json_decode($v['test6'],true); 26 } 27 //处理需要返回的数组 28 return $res; 29 }else return false;
    30 }

    /******利用php的array_slice函数实现编号的随机选择******/

     1     /*
     2      * function getTenNum( int $min, int $max, int $num)
     3      * 生成一定数量的随机数
     4      * $min 和 $max: 指定随机数的范围
     5      * $num: 指定生成数量
     6      */
     7     public function getRandArray($min,$max,$num){
     8         $array = range($min,$max);
     9         shuffle($array);
    10         $array = array_slice($array, -$num);
    11         return $array;
    12     }

    /******选手抢答题目逻辑的实现******/

     1     /**
     2      * @desc    选手进行题目的抢答
     3      * @date    2017/4/19 18:19
     4      * @param   [$id $uid]
     5      * @author  十月桂花香十里
     6      * @return  [bool or array]
     7      */
     8     public function userQuickAnswer($id='',$uid){
     9         //判断uid是否是答题选手
    10         if(!in_array($uid, config('test1.check_uid'))) return false;
    11         //判断$id是否存在
    12         if($id < config('test1.start_quick_id') || $id > config('test1.end_quick_id')) return false;
    13         //redis判断题目是否可以进行抢答
    14         $redis = PRedis::connection('default');
    15         $check_quick_status = $redis->get("check_quick_id_".$id);
    16         if($check_quick_status ==1){
    17             //运用事务,添加共享锁
    18             //DB::transaction(function () use ($redis,$id){
    19                 //将redis的状态和数据库field3改为0,变为不可抢答
    20                 //DjmQuestion::where('id',$id)->sharedLock()->update(['test1'=>0]);
    21             //});
    22             //将redis的状态改为0,变为不可抢答
    23             $redis->set("check_quick_id_".$id,0);
    24             //redis绑定此题和选手的关系
    25             $redis->set("check_quick_id_".$id."_".$uid,1);
    26             //获取本条数据记录
    28 return DjmQuestion::find($id)->toArray();
    29 }else return false; 30 }

    /******选手抢答题目回答的实现******/

     1     /**
     2      * @desc    选手进行抢答题的回答
     3      * @date    2017/4/20 10:09
     4      * @param   [$id,$uid]
     5      * @author  1245049149@qq.com
     6      * @return  [bool or array]
     7      */
     8     public function userQuickAnswerResult($id,$uid,$answer){
     9         //判断uid是否是答题选手
    10         if(!in_array($uid, config('djm.check_uid'))) return false;
    11         //判断$id是否存在
    12         if($id < config('djm.start_quick_id') || $id > config('djm.end_quick_id')) return false;
    13         //redis判断此题和选手是否绑定关系
    14         $redis = PRedis::connection('default');
    15         $check_user_quick_status = $redis->get("check_quick_id_".$id."_".$uid);
    16         if($check_user_quick_status == 1){
    17                //关系如果已经绑定,判断选手答题情况
    18                 $redis->set("check_quick_id_".$id."_".$uid,0);
    19                 $check_answer = config('djm.check_answer'); //题目编号答案对照(如果题目数量不多且固定的话,建议写进配置文件中,不用查询数据库)
    20                 if($check_answer[$id] == strtoupper($answer)){
    21                     //回答正确分数自加5
    22                     DjmQuestionScore::where('test10',$uid)
    23                         ->where('test11',config('djm.quick_test11'))
    24               ->increment('test12',5); 25 return array( 26 'msg' => '回答正确', 27 'status' => 1, 28 ); 29 }else{ 30 //回答错误分数自减5 32 DjmQuestionScore::where('test10',$uid) 33  ->where('test11',config('djm.quick_test11'))
    34               ->decrement('score',5); 35 return array( 36 'msg' => '回答错误,正确答案:'.$check_answer[$id], 37 'test12' => $check_answer[$id], 38 'status' => 0, 39 ); 40 } 41 }else return false; 42 }

    ok,功能至此实现了。

  • 相关阅读:
    缺省源
    MySQL曹操外卖一
    MySQL曹操外卖二
    正确使用MySQL外键约束
    html大部分实用标签(结构型)
    html超级基础标签
    我的简单作业
    章节课程复习笔记
    FC超级玛丽研究(NES游戏)
    二维码生成
  • 原文地址:https://www.cnblogs.com/qwgshare/p/6780465.html
Copyright © 2020-2023  润新知