【解决方案+问题分析】微信分销会员上下级关系出现混乱,剖析全过程

微信分销会员上下级关系出现混乱,从反馈到分析问题如何发生 ,再到若是解决。在此把实际项目遇到的问题分享出来,以供之后和网友参考。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检查及解决方案就到此结束了,过程当中一些细节性东西不太好描述,最好去实际实践一下,或者是实际用到时慢慢体会。

相关文章
相关标签/搜索