1. 程式人生 > 資料庫 >【PHP】PHP程式碼處理(普通/不重要的)併發情況,例如pv統計(不使用MySQL行或表鎖、避免程式冗餘)

【PHP】PHP程式碼處理(普通/不重要的)併發情況,例如pv統計(不使用MySQL行或表鎖、避免程式冗餘)

1、PHP程式碼處理(普通/不重要的)併發情況,例如統計pv資料:什麼意思呢?

比如pv統計,某時間段pv資料不存在則新增,存在則更新+1,這時候會存在一個問題:我們查詢的時候可能沒有記錄,但是準備插入的時候卻已經有資料了(別的程序捷足先登)

解決辦法:我們可以在MySQL設定 唯一主鍵,配合php程式碼進行控制,使用 try catch 捕獲MySQL的異常,匹配異常程式碼,將重複的一行進行更新

/**
     * 頁面pv統計
     */
    public function statPv(Request $request)
    {
        $node_id = $request->node_id ?? config('cache.master_node_id');
        $openId = $request->input('open_id');
        $event = Input::get('event') ?? '';
        $route = Input::get('route') ?? '';
        $data = S::show($route);

        if($event != 'show'){
            return S::jsonReturn( ['info'=>'fail~~'] );
        }
        $sessionKey = $request->input('3rd_session');
        if(empty($openId) || empty($sessionKey)){
            return S::jsonReturn( ['info'=>'fail'] );
        }
        $userInfo = unserialize(WeChatDao::baseRedis('get',  ':' . $openId . '_cache'));
        $sysSessionKey = unserialize(WeChatDao::baseRedis('get',  ':key:' . md5($sessionKey)));
        if(empty($sysSessionKey)){
            return S::jsonReturn( ['info'=>'fail~'] );
        }
        if(empty($userInfo)){
            return S::jsonReturn( ['info'=>'fail!'] );
        }
        if ($userInfo['open_id'] != $sysSessionKey['openid']) {
            return S::jsonReturn( ['info'=>'fail!!'] );
        }

        $url = $data['path'];
        $query = $data['query'];
        $trans_date = date('Y-m-d');
        $trans_hour = date('H') . ':00';
        
        $pvObj = StatPageVisitDay::where('node_id',$node_id)->where('trans_date',$trans_date)->where('trans_hour',$trans_hour)->where('url',$url)->first();
        if(!empty($pvObj)) {
            $pvObj->increment('pv');
        } else {
            $pvObj = new statPageVisitDay();
            $pvObj->node_id = $node_id;
            $pvObj->trans_date = $trans_date;
            $pvObj->trans_hour = $trans_hour;
            $pvObj->pv = 1;
            $pvObj->url = $url;
            $pvObj->param = $query;
            try {
                $pvObj->save();
            } catch (\Exception $e) {
                $message = $e->getMessage();
                if (strstr($message, "Duplicate") && strstr($message, "for key ")) {
                    log_write('插入pv表主鍵或唯一索引重複,再次執行更新操作' . $message);
                    StatPageVisitDay::where('node_id',$node_id)->where('trans_date',$trans_date)->where('trans_hour',$trans_hour)->where('url',$url)->increment('pv');
                } else {
                    log_write("PV入庫異常,原因{$e->getMessage()}");
                    MailDao::warning("pv統計異常. 頁面uri={$route},", json_encode(['err_msg'=>$e->getMessage()]));
                    return S::jsonReturn( ['info'=>'statpv insert failed'] );
                }
            }
        }

        return S::jsonReturn( ['info'=>'success'] );
    }