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); } }