文章目录
  1. 1. 文档更新说明
  2. 2. 前言
  3. 3. 用户注册
    1. 3.1. 手机号注册
    2. 3.2. 第三方帐号注册
  4. 4. 帐号绑定
    1. 4.1. 手机号未注册
    2. 4.2. 手机号已注册
  5. 5. 数据迁移
  6. 6. 数据查询

文档更新说明

  • 2016-03-26 完成
  • 2016-03-25 初稿

前言

  在可绑定可扩展的帐号系统设计原理及其实现(一)一文中已经啰嗦讲完原理了.本文主要借用PHP代码从实现角度讲述.分成用户注册,帐号绑定,数据迁移,数据查询四个部分.   

用户注册

手机号注册

  手机号注册的帐号,称为主帐号,实现起来相对比较简单,只需要在users表中插入一条主帐号数据即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
///UsersModel类
/**
* 主帐号注册
* @desc 成功时返回用户id
*/
public function addOne($data) {
if ( isset($data['phone']) && isset($data['nickname']) ) {
$data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s',time());
//这里需要事务支持
$this->db->query("BEGIN");
try{
if($this->db->insert($this->_tablename,$data)){
$last_id = $this->db->Insert_ID();
$where_string = 'id = '.$last_id;
$this->db->update($this->_tablename,array('nickname'=>$last_id),$where_string,1);
//写入资金表,由另一个模型封装,只需要传入uid就好,忽略细节.
$accModel = new AccountModel();
$accResult = $accModel->addOne($last_id);
if (!$accResult) {
throw new Exception("Can not insert to accounts");
}
}else{
throw new Exception("Can not insert to users");
}

$this->db->query("COMMIT");
return $last_id;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
//打印日志,自定义的函数.
log_result("Roll back : ".$e->getMessage);
return false;
}
}
return false;
}

第三方帐号注册

  第三方帐号注册相对手机号注册要复杂一点点.先在open_users中插入第三方帐号信息,接着在users表中插入一条占位数据,最后在user_aliases中插入一条自关联数据,这样查询数据就可以不区分登录的帐号是主帐号还是第三方帐号.由于users表中的phone是唯一非空字段,所以占位数据的phone自动采用虚拟的方式phone=v+第三方表记录id.
  注册第三方帐号时在users表中的占位数据在绑定手机号时,如果手机号从未注册,那这条记录也会变成主帐号,如果手机号已经注册过了,这条记录才是真正作废.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
///OpenUsersModel类
/**
* 第三方帐号注册
* @desc 成功时返回用户id
*/
public function addOne($data) {
//open_users表id
$ouid = 0;
//users表id
$user_id = 0;
if (isset($data['nickname']) && isset($data['openid']) && isset($data['genre'])){
$data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s',time());
$openuserData = [];
$openuserData['openid'] = $data['openid'];
$openuserData['genre'] = $data['genre'];
$openuserData['created_at'] = $openuserData['updated_at'] = $data['created_at'];
$this->db->query("BEGIN");
try {
if($this->db->insert($this->_tablename,$openuserData)){
$ouid = $this->db->Insert_ID();
//在用户表中写入占位信息
$vphone = "v{$ouid}";
$userData = [];
$userData['avatar'] = $data['avatar'];
$userData['nickname'] = $data['nickname'];
$userData['phone'] = $vphone;
$userData['created_at'] = $userData['updated_at'] = $data['updated_at'];
if(!$this->db->insert('users',$userData)){
throw new Exception("Can not insert to users");
}
$user_id = $this->db->Insert_ID();
//取得user id之后,开始写入资金表和第三方表中对应的数据
//写入资金表
$accModel = new AccountModel();
if (!$accModel->addOne($user_id)) {
throw new Exception("Can not insert to accounts");
}

//在第三方表中更新获取到的user_id
$where_string = 'id = '.$ouid;
if(!$this->db->update($this->_tablename,array('user_id'=>$user_id),$where_string,1)){
throw new Exception("Can not update open_users");
}

//最后将userid 插入到ID关系表中,这里比较特殊,因为用户第一次进入微信,此时未绑定手机号码
//所以还不知道用户主id,因此主id和占位id认为是相同的并且插入到关系表中

//主id(主帐号uid):用户已经绑定了手机号码所在记录的id
//占位id(第三方uid):用户第一次微信登录后,系统自动在users表中追加的phone=v+ouid的一条记录所在的id
$aliasesData = [];
$aliasesData['alias_user_id'] = $aliasesData['user_id'] = $user_id;
if(!$this->db->insert('user_aliases',$aliasesData)){
throw new Exception("Can not insert to alias_user_id");
}
}else{
throw new Exception("Can not insert to open_users");
}
$this->db->query("COMMIT");
return $user_id;
} catch (Exception $e) {
$this->db->query("ROLLBACK");
log_result("Roll back : ".$e->getMessage);
exit;
}
}
return false;
}

帐号绑定

  用户登录第三方帐号后,操作绑定手机号码时,先检查用户给出的phone是否存在users表的phone字段.手机号码可能已经存在主帐号中也可能是一个全新的号码,所以帐号绑定分成两种情况,下面分别说明.

手机号未注册

  手机号码从未注册过,说明手机号码不存在users表中.所以第三方帐号在users表中的占位数据可以直接更新为主帐号->直接将users表中phone字段更新为绑定的手机号即可.

手机号已注册

  对于手机号已经注册过的,先找到手机号所在行id(也就是主id),把主id更新到open_users表的user_id字段,然后在user_aliases表中追加一条记录:

1
2
3
4
$aliasesData = [];
$aliasesData['user_id'] = 主id;
$aliasesData['alias_user_id'] = 占位id;
$this->db->insert('user_aliases',$aliasesData);

数据迁移

  由于表结构已经做了设计优化,数据迁移时,只需要在accounts表中,把第三方帐号中的数据转入主帐号中就可.至于其他消费记录购买记录等等一概不需要做任何改动~😋

数据查询

  最后一部分就是数据查询了.根据数据库的设计,我们只需要得到任何一个第三方uid或者主帐号uid,即可从user_aliases表中反查出所有的关联id,然后只需要在任何需要查询记录的表中使用SQL的in语法即可查询到数据.

1
2
3
//伪代码
$sql = "select feature from `orders` where `orders`.user_id in (id1, id2, id3, ...)";
$some_data = $this->db->executeS($sql);
文章目录
  1. 1. 文档更新说明
  2. 2. 前言
  3. 3. 用户注册
    1. 3.1. 手机号注册
    2. 3.2. 第三方帐号注册
  4. 4. 帐号绑定
    1. 4.1. 手机号未注册
    2. 4.2. 手机号已注册
  5. 5. 数据迁移
  6. 6. 数据查询