我服務(wù)端是采用Workerman+GatewayWorker+TP5
在使用中,如果并發(fā)不高的話,基本沒問題,
但是一但有高并發(fā)時,同時需要插入或更新批量數(shù)據(jù)時,有時會出現(xiàn)鎖表或者違反唯一約束了,
我已經(jīng)在插入時先判斷是否存在記錄了,不存在才整合起來,一起插入的。
$remindData=[];//提醒庫
//評論
$commentData=[];
$commentUserList=isset($objectItem['commentUserList'])?$objectItem['commentUserList']:[];//文章和相關(guān)評論和點贊的數(shù)據(jù)
if($commentUserList){
$commentUserList=array_column($commentUserList,null,'commentId');
$commentIds=array_column($commentUserList,'commentId');
$commentList=MomentsComment::where('object_id="'.$object_id.'"')
->where('commentId','in',$commentIds)
->select();
$commentList=collection($commentList)->toArray();
$commentList=array_column($commentList,null,'commentId');
foreach ($commentUserList as $ck=>$cv){
if(!isset($commentList[$cv['commentId']])){
$commentData[]=[
'object_id'=>$object_id,
'userid'=>$cv['username'],
'commentFlag'=>$cv['commentFlag'],
'commentId'=>$cv['commentId'],
'replyCommentId'=>$cv['replyCommentId'],
'reply_userid'=>$cv['replyUsername'],
'source'=>$cv['source'],
'type'=>$cv['type'],
'content'=>$cv['content'],
'createTime'=>$cv['createTime']
];
if($robot_userid==$friends_userid){
$wx_key=$robot_userid.'##'.$cv['username'];
$reply_wx_key=($cv['replyUsername']!=''?$robot_wxid.'##'.$cv['replyUsername']:'');
$remindData[]=[
'object_id'=>$object_id,
'wx_key'=>$wx_key,
'robot_userid'=>$robot_userid,
'friends_userid'=>$cv['username'],
'typ'=>($cv['replyCommentId']!=0?2:1),
'commentId'=>$cv['commentId'],
'replyCommentId'=>$cv['replyCommentId'],
'reply_wx_key'=>$reply_wx_key,
'reply_userid'=>$cv['replyUsername'],
'content'=>$cv['content'],
'remind_time'=>$cv['createTime']
];
}
}
}
}
//點贊
$likeData=[];
$likeUserList=isset($objectItem['likeUserList'])?$objectItem['likeUserList']:[];
if($likeUserList){
$likeUserList=array_column($likeUserList,null,'like_userid');
$LikeUserids=array_column($likeUserList,'like_userid');
$LikeList=MomentsLike::where('object_id="'.$object_id.'"')
->where('like_userid','in',$LikeUserids)
->select();
$LikeList=collection($LikeList)->toArray();
$LikeList=array_column($LikeList,null,'like_userid');
foreach ($likeUserList as $ik=>$iv){
if(!isset($LikeList[$iv['username']])){
$likeData[]=[
'object_id'=>$object_id,
'like_userid'=>$iv['username'],
'like_time'=>$iv['createTime']
];
//判斷如果此文章是自已的,則入提醒庫
if($robot_userid==$friends_userid){
$wx_key=$robot_userid.'##'.$iv['username'];
$remindData[]=[
'object_id'=>$object_id,
'wx_key'=>$wx_key,
'robot_userid'=>$robot_userid,
'friends_userid'=>$iv['username'],
'remind_time'=>$iv['createTime'],
];
}
}
}
}
$saveData=[
'object_id'=>$object_id,
'userid'=>$friends_userid,
'commentCount'=>$objectItem['commentCount'],
'createTime'=>$objectItem['createTime'],
'likeCount'=>$objectItem['likeCount'],
'nickname'=>$objectItem['nickname'],
'conents'=>$objectItem['contentDesc'],//文字內(nèi)容
];
$result=false;
$snsItem=Moments::where('object_id="'.$object_id.'"')->find();//這是文章表
if(!$snsItem){
$wm=new Moments();
$result=$wm->save($saveData);
}
$execArr=[];
if($commentData){
$wmc=new MomentsComment();//這是評論
$wmc->saveAll($commentData);
}
if($likeData){
$wml=new MomentsLike();//這是點贊
$wml->saveAll($likeData);
}
$is_remind=false;
if($remindData){
$wmr=new MomentsRemind();//這是如果是自已發(fā)的,則加入提醒
$wmr->saveAll($remindData);
$is_remind=true;
}
之前也有使用INSERT IGNORE INTO來插入,不過也不是理想,想問下,像這種的在高并發(fā)下時要如何避免出現(xiàn)鎖表或唯一約束呢。
最好隊列處理 這種插入和修改 用隊列,要不然沒啥好辦法
我已在onWorkerStart里定義了隊列
$redisQueue->subscribe('CommentNotify',function($message)use($redis,$bWorker){
Common::CommentNotify($message,$redis,$bWorker);
});
然后在OnMessage里將收到的信息加入隊列里。
$redisQueue->send(‘CommentNotify’,$data);
但是由于是多進程,所以當并發(fā)時,就會有多個進程同時在處理,這就會導致鎖表或出現(xiàn)主建唯一沖突問題。
不知還有其它方案否。
可以考慮增加一個寫鎖,讓插入按順序進行(有鎖的情況下間隔x秒重新發(fā)布隊列)。
或者給插入記錄生成一個主健id, 比如使用
$redis->incr('you table max id');