【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'] );
    }

 

上一篇:项目js java 实现自动复制粘贴 亲测有效


下一篇:接口隔离原则(ISP)