【解決方案+問題分析】微信分銷會員上下級關係出現混亂,剖析全過程

微信分銷會員上下級關係出現混亂,從反饋到分析問題如何發生 ,再到若是解決。在此把實際項目遇到的問題分享出來,以供之後和網友參考。php


某日,接到一通領導打來的一通電話。電話主要內容是他曾接到一個用戶的反饋電話,說道咱們有一個項目中,微信會員上下級關係存在混亂,用戶a關注的用戶b,用戶b卻關注的用戶的a。上下級關係很亂,還有不少用戶存在一些,用戶a關注了用戶b,用戶b的推薦好友列表中卻沒有用戶a的存在……web

當我拿到這個問題以後,首先的態度非常質疑,代碼應該都是沒有問題的,可能會存在一些數據沒有對上。此處我須要在整個數據庫中查找出全部的上下級混亂關係的會員。sql

什麼是上下級混亂關係?數據庫

  1. 用戶b的上級是用戶a,用戶a的上級是用戶b。(b>a>b)服務器

  2. 用戶c的上級是用戶b,用戶b的上級是用戶a,用戶a的上級是用戶c。(c>b>a>c)
    微信

所謂的混亂即是出現了這種無線循環的關係,那麼,若是查找出來這種上下級關係呢?框架

怎麼解決?函數

根據以上的舉例,可以很明顯的能看出來一個規律即是這種會員關係中,一圈之中至少存在兩個會員的?本身上級的上級……的上級有多是本身。只要找出本身全部的上級來查詢是否存在兩個相同會員就行了。測試

首先寫一個腳原本執行,若是web執行超時,可採用命令行方式執行。this

如下以TP框架語法進行舉例:

/**
	 * 排錯函數
	 */
	public function member_level(){
		$Model = M('weishop_member');
		
		//查詢出全部有上級的用戶
		$exist_sql = "SELECT wm_id,wm_parent_id FROM weishop_member WHERE wm_parent_id !=0";
		$exist_parent_users = $Model->query($exist_sql);
//		debug_show($exist_parent_users);
		$num = 0;
		$error_users = array();
		foreach($exist_parent_users as $val){
			//此處屏蔽的代碼能夠在調試時放開,測試數據是否正常,避免邏輯錯誤致使死循環超時
//			if($num==2){
//				exit;
//			}
			$user_status = $this->level_debug($val['wm_id'],$val['wm_parent_id'],true);
			if($user_status===3){
				$error_users[] = $val['wm_id'];
			}
			$num++;
		}
		echo '<br/>error users:'.implode(',', $error_users).'<br/>';
		echo '<br/>Check OK!';
		//拿出一個數據來進行 測試排錯
//		$this->level_debug($exist_parent_users[0]['wm_id'],$exist_parent_users[0]['wm_parent_id'],true);
		echo 'Exist users number:'.count($exist_parent_users);
		
	}
	/**
	 * 遞歸排錯
	 * @desc  查詢當前用戶的上級祖(祖父)中是否存在循環(兒子)
	 * @param  $wm_id     會員id
	 * @param  $parent_id 上級id
	 * @param  $init      是否初始化,即首次執行
	 * @return  1:用戶正常。0:用戶還有上級。3:用戶關係出錯
	 */
	private function level_debug($wm_id,$parent_id,$init=false){
		static $user_id = 0;//被檢查的用戶
		static $_son = array();//兒子組
		static $num = 0;//循環執行次數
		
		//empty  若是是初始化執行則清空
		if($init){
			$_son = array();
			$num = 0;
			$user_id = $wm_id;
		}
		$num++;
		if(!isset($_son[$wm_id])){
			//若是兒子組中不存在當前用戶,則加入當前用戶,繼續向下查找祖父
			$_son[$wm_id] = array(
				'wm_id'=>$wm_id,
				'wm_parent_id' => $parent_id
			);
		}
		//調試時測試執行次數,防止邏輯錯誤,出現死循環超時
		if($num==5){
//			debug_show($wm_id);
//			debug_show($_son);
		}
		$Model = M('weishop_member');
		
		//查詢當前上級
		$query_parent_sql = "SELECT wm_id,wm_parent_id FROM weishop_member WHERE wm_id = '$parent_id'";
		$parent_user = $Model->query($query_parent_sql);
		//若是上級存在 而且上級用戶還有上級則繼續遞歸
		
		//條件:1.當前用戶上級存在。2.上級用戶還存在上級
		if(is_array($parent_user) && isset($parent_user[0]) && $parent_user[0]['wm_parent_id']!=0){
			$buf = $parent_user[0];
			
			//若是當前用戶上級的上級存在於兒子組中則進入判斷
			if(isset($_son[$buf['wm_parent_id']])){
				echo '<font color="red">error!</font> user id:'.$user_id.'&nbsp;&nbsp;'.'parent_id :'.$buf['wm_id'].'&nbsp;&nbsp;'.'parent includes '
				.implode(',', array_keys($_son)).' execute:'.$num .'<br/> ';
				return 3;
//				exit;
			}
			//符合條件 繼續進入循環探尋祖父
			$this->level_debug($buf['wm_id'],$buf['wm_parent_id']);
			return 0;
		}
		//數據量過多,則關閉正經常使用戶結果顯示
//		echo 'user id:'.$user_id.'&nbsp;&nbsp;'.'parent_id :'.$parent_id.'&nbsp;&nbsp;'.'parent includes '
//		.implode(',', array_keys($_son)).' execute:'.$num .'<br/> ';
		return 1;
	}

以上代碼通過屢次修改後的,並非一鼓作氣。須要用到的朋友能夠仔細分析下邏輯。

通過屢次的修改,以上的代碼沒有超時執行,跟用戶數量仍是有關係,畢竟只有幾千個。返回的內容以下:

說明一下,紅色error都是關係混亂的用戶,在最後咱們能夠看到出錯的用戶抱(bāo)括2和116。所存在上級的用戶總共有3158個。

那麼問題看來都是由2和116的關係混亂致使的,只須要將他們更正後便可。以後便聯繫了用戶id分別爲2和116的用戶,將他們的註冊時間和推薦時間作一瞭解,將2的上級清空,恢復爲0.

那麼再執行剛纔的排錯來看看結果。

此次檢查以後,發現並無關係混亂的用戶。一切恢復平靜。雖說目前的問題解決了,但並不意味着,之後都會正常,問題的根源尚未找出來。

怎麼修復?

帶着問題繼續在代碼中尋找,來到會員綁定的邏輯處。

/**
	 * 綁定微信上下級(未修復)
	 * @param   $openid    當前用戶openID
	 * @param   $parent_id 上級用戶id
	 * @return  bool
	 */
	 public function bingding($openid,$parent_id){
	 	//檢測當前用戶是否有上級而且上級不能爲本身,沒有則繼續 
	 	$res = $this->where("wm_openid ='$openid' && wm_id != '$parent_id' && wm_parent_id ='0'")->save(array("wm_parent_id" => $parent_id));
		if($res){
			return true;
		}
	 }
	 

粗略一看幾乎看不出來啥問題,綁定時首先判斷的是當前用戶的上級是否存在,若是有天然不能附加上級了。若是沒有的狀況下,而且上級不能爲本身,不然本身跟本身成爲上級就亂了套。當時寫的代碼本覺得是正常。結果出了一個隱性bug。

怎麼發生的呢?

上面的邏輯會忽略掉,下級下級的用戶偶然一天變成本身的上級(多是由於本身失誤的去掃碼,掃了本身辛辛苦苦下級用戶的碼,反而讓下級成爲了本身的上級),致使關係混亂,在用戶方面可能會致使佣金等利益計算錯誤,在平臺層面會影響一筆損失,在此能夠給各位一個提醒,凡是跟錢有關的必定要慎重!

至於修復呢,而此處只須要增長一層判斷便可解決。

修改後代碼奉上:

/**
	 * 綁定微信上下級(已修復)
	 * @param   $openid    當前用戶openID
	 * @param   $parent_id 上級用戶id
	 * @return  bool
	 */
	 public function bingding($openid,$parent_id){
	 	//檢測是否有下級
		$sql = "SELECT count(a.wm_id) as count FROM `weishop_member` as a  join `weishop_member` as b on a.wm_parent_id = b.wm_id WHERE b.wm_openid='{$openid}';";
	 	
	 	$count_res = $this->query($sql);
		if(is_array($count_res) || count($count_res)==1){
			if(isset($count_res[0]['count']) && $count_res[0]['count']>0){
				return false;
				//若是有下級則不能成爲別人的下級
			}
		}
		
	 	//檢測當前用戶是否有上級而且上級不能爲本身,沒有則繼續 
	 	$res = $this->where("wm_openid ='$openid' && wm_id != '$parent_id' && wm_parent_id ='0'")->save(array("wm_parent_id" => $parent_id));
		if($res){
			return true;
		}
	 	return false;
	 }

若是本身已經有了下級用戶就不能成爲別人的下級,這樣一來,就不會出現這種死循環。固然解決的方案不僅是這一個,符合業務邏輯就好。

修改好代碼檢查無誤後當即將代碼更新至服務器,以防止出現更多差錯。

基本上這次的bug檢查及解決方案就到此結束了,過程當中一些細節性東西不太好描述,最好去實際實踐一下,或者是實際用到時慢慢體會。

相關文章
相關標籤/搜索