• PHP 使用redis set锁


    const LOCKRSETUSR = 'lockuser';

    const SETNXKEYS = 'user_nx_%s'; 

    const NOT_FREQUENT_OPERATION = '请勿频繁操作,请等待%s s';

    //防刷:防止重复刷新页面,加锁随机码产生变动无法解锁
            $setnxkeys = sprintf(self::SETNXKEYS,$edata['uid']); //$data['uid'] 操作用户的uid
            if($this->redis->exists($setnxkeys)) {
                $ttlsecond = sprintf(self::NOT_FREQUENT_OPERATION,$this->redis->ttl($setnxkeys));
                returnJson(['status' =>0, 'msg' => $ttlsecond]);
            }else{
                $this->redis->set($setnxkeys, 1, 7);
            }
    

      

    //加锁

    $token = rand(1, 100000);
    $locksetkey = $this->redis->lockset(self::LOCKRSETUSR, $token);

    //解锁
    $this->redis->unlockset(self::LOCKRSETUSR, $token);

    具体redis类方法

    加锁

    public function lockset($cachekey, $value, $expire_time=6) {
             return $this->handler->set($cachekey, $value, ['NX', 'EX'=>$expire_time]);
         }

     解锁:

    public function unlockset($cachekey,$token) {
            
            $script = 'if redis.call("get",KEYS[1]) == ARGV[1]
            then
                return redis.call("del",KEYS[1])
            else
                return 0
            end';
            return $this->handler->eval($script, [$cachekey, $token],1);
    
    }

    PHP中使用redis执行lua脚本示例

    $this->handler->eval($script, [$cachekey, $token],1);
    eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

    解释: "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 是被求值的 Lua 脚本,数字 2 指定了键名参数的数量, key1 和 key2 是键名参数,
    分别使用 KEYS[1] 和 KEYS[2] 访问,而最后的 first 和 second 则是附加参数,可以通过 ARGV[1] 和 ARGV[2] 访问它们。

    PHP中使用redis拓展执行脚本时,eval方法的参数 3个,第一个是脚本代码,第二个是一个数组,参数数组,第三个参数是个整数,表示第二个参数中的前几个是key参数,剩下的都是附加参数

     

    实际案例:

       const NO_DATA                = '参数不能为空!';
        const NO_COMMEM_TCONTENT     = '内容不能为空!';
        const NOT_LOGIN              = '请登录!';
        const NOT_FREQUENT_OPERATION = '请勿频繁操作,请等待%s s';
        const SETNXKEYS              = 'user_nx_%s';
        const LOCKRSETUSR            = 'lockuser';
    

      

    /**
         * 抽奖接口
         * @Author   方法
         * @DateTime 2020-01-14T10:50:02+0800
         * @param
         * @return   [type]                   [description]
         */
        public function lucky()
        {
            $post_params = [
                ['type' => 'int', 'name' => "uid"], //用户id
                ['type'=>'string','name'=>"loginId"],//logid
            ];
            
            if (!$this->request->post("data")) {
                returnJson(['status' => LuckyDrawSevice::STATUS_EROOR, 'result' => 0, 'msg' => self::NO_DATA],$this->client_refer);
            }
            $edata = postEmpty($this->request->post('data'), $post_params,$this->client_refer);
            if(empty($edata['uid']) || empty($edata['loginId'])) {
            returnJson(['status' => LuckyDrawSevice::STATUS_EROOR,'result' => 0, 'msg' => self::NOT_LOGIN],$this->client_refer);
            } else {
            UserAuth($edata['uid'], $edata['loginId']);
            }
    
            //防刷:防止重复刷新页面,加锁随机码产生变动无法解锁
            $setnxkeys = sprintf(self::SETNXKEYS, $edata['uid']);
            if ($this->redis->exists($setnxkeys)) {
                $ttlsecond = sprintf(self::NOT_FREQUENT_OPERATION, $this->redis->ttl($setnxkeys));
                returnJson(['status' => LuckyDrawSevice::STATUS_EROOR,'result' => 0, 'msg' => $ttlsecond],$this->client_refer);
            } else {
                $this->redis->set($setnxkeys, 1, 1); // 设置用于id key值
            }
    
            //加锁
            $token      = rand(1, 100000);
            $locksetkey = $this->redis->lockset(self::LOCKRSETUSR, $token);
            if ($locksetkey) {
              
                $whether_to_win = $this->luckysevice->luckyJudge($edata);
                try {
    
                    if (!$whether_to_win['status']) {
                        //解锁
                        $this->redis->unlockset(self::LOCKRSETUSR, $token);
                        returnJson(['status' => LuckyDrawSevice::STATUS_EROOR,'result' => 0, 'msg' => $whether_to_win['msg']],$this->client_refer);
                    } else {
                        $isrecordwhere = ['uid' => $edata['uid'], 'is_deleted' => 0];
                        $isrecorduser  = Db::table('lucky_user_raffle_record')->where($isrecordwhere)->find();
                        $userreal      = Db::table('user')->where('id', $edata['uid'])->field('real_name,certificate')->find();
                        $recordarr     = [
                            'uid'         => $edata['uid'],
                            'real_name'   => $userreal['real_name'],
                            'certificate' => $userreal['certificate'],
                        ];
                        $uprecod = '';
                        //中奖奖品个数加1
                        if ($whether_to_win['result']) {
    
                            if ($whether_to_win['result'] < 6) {
                                $recordarr['prize_name'] = $whether_to_win['result'];
                                $bigprises               = 'num_awards';
                            } else {
                                $bigprises = 'num_lucky_awards';
                            }
                           
                            if (!empty($isrecorduser)) {
                                $recordarr[$bigprises] = $isrecorduser[$bigprises] + 1;
                                $uprecod               = Db::table('lucky_user_raffle_record')->where($isrecordwhere)->update($recordarr);
                                if(!$uprecod) {
                                     Db::rollback();
                                     returnJson(['status' => LuckyDrawSevice::STATUS_EROOR, 'result' => 0, 'msg' => '抽奖失败'],$this->client_refer);
                                }
                            } else {
                                $recordarr[$bigprises] = 1;
                                $uprecod   = Db::table('lucky_user_raffle_record')->insert($recordarr);
                                if(!$uprecod) {
                                     Db::rollback();
                                     returnJson(['status' => LuckyDrawSevice::STATUS_EROOR, 'result' => 0, 'msg' => '抽奖失败'],$this->client_refer);
                                }
                            }
                            if (isset($recordarr['prize_name'])) {
                                unset($recordarr['prize_name']);
                            }
                            unset($recordarr[$bigprises]);
    
                        }
                        $recordarr['raffle_records'] = $whether_to_win['result'];
                        //加入日志表
                        $insertrecod = Db::table('lucky_user_lottery_log')->insert($recordarr);
    
                        if ($insertrecod) {
                            Db::commit();
                            returnJson(['status' => LuckyDrawSevice::STATUS_SUCESS, 'result' => $whether_to_win['result'], 'msg' => '抽中' . $whether_to_win['result'] . '等奖'],$this->client_refer);
                        } else {
                            Db::rollback();
                            returnJson(['status' => LuckyDrawSevice::STATUS_EROOR, 'result' => 0, 'msg' => '抽奖失败'],$this->client_refer);
                        }
                        //解锁
                        $this->redis->unlockset(self::LOCKRSETUSR, $token);
                    }
                } catch (Exception $e) {
                    Db::rollback();
                    //解锁
                    $this->redis->unlockset(self::LOCKRSETUSR, $token);
                    returnJson(['status' => LuckyDrawSevice::STATUS_EROOR, 'result' => 0, 'msg' => $e->getMessage()],$this->client_refer);
                }
            }else{
                 returnJson(['status' => LuckyDrawSevice::STATUS_EROOR,'result' => 0, 'msg' => '请稍后再试'],$this->client_refer);
            }
    
        }
  • 相关阅读:
    AFN 控制字符报错(无法解析)
    HTTP POST请求报文格式分析与Java实现文件上传
    xcrun
    Makefile选项CFLAGS,LDFLAGS,LIBS
    Xcode 编译错误
    iOS 11 适配
    机器学习算法之决策树
    Python extend 和 append 的区别
    Python warning_function name should be lowercase
    使用matplotlib绘制导数图像
  • 原文地址:https://www.cnblogs.com/yszr/p/12189923.html
Copyright © 2020-2023  润新知