本文介绍 MySQL45 讲中提到的一个用户关注的案例,并记录下可行的处理方案。
业务背景
业务上有这样的需求,A、B两个用户,如果互相关注,则成为好友。存在两个表,
关系(relation)表:
CREATE TABLE relation
(
id
int NOT NULL AUTO_INCREMENT,
user_id
int NOT NULL,
liker_id
int NOT NULL,
PRIMARY KEY (id
),
UNIQUE KEY uk_user_id_liker_id
(user_id
,liker_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
好友(friend)表:
CREATE TABLE friend
(
id
int NOT NULL AUTO_INCREMENT,
friend1_id
int NOT NULL,
friend2_id
int NOT NULL,
PRIMARY KEY (id
),
KEY uk_friend
(friend1_id
,friend2_id
) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
以A关注B为例:
第一步,先查询对方有没有关注自己(B有没有关注A)
select * from relation where user_id = B and liker_id = A;
如果有,则成为好友
insert into friend;
不,这只是一段单向的关系。
[En]
No, it’s just an one-way relationship.
insert into like;
现在存在的问题是, 如果 A 和 B 同时关注对方,在第一步判断对方没有关注自己,则只记录单向关注关系,然而实际上应该记录成好友的。
锁定记录就能解决吗?否,由于该记录不存在,行锁无法生效。
[En]
Can it be solved by locking the records? No, because the record does not exist, the row lock cannot take effect.
解决方案
将两条记录合并到一条,这样就可以充分利用唯一索引。此外,再新增一个字段来记录状态。
关系表新增一个 relation_ship 字段,tinyint 类型。当 A 关注 B 且 A < B 时,
INSERT INTO (user_id, liker_id, relation_ship) values(A, B, 1);
当 A 关注 B 且 B < A 时,
INSERT INTO (user_id, liker_id, relation_ship) values(B, A, 2);
当 relation_ship = 3,表示 A 和 B 互相关注。
执行逻辑如下
begin;
1. 插入记录或者更新 relation_ship
INSERT INTO relation(user_id, liker_id, relation_ship) values(A, B, 1) on duplicate key update relation_ship = (relation_ship | 1);
2. 查询 relation_ship
SELECT relation_ship FROM relation WHERE user_id = A AND liker_id = B;
3. 在业务逻辑中,如果 relation_ship = 3,则创建好友关系
INSERT INTO friend(friend1_id, friend2_id) values(A, B);
commit;
当两个用户同时关注对方时,对先执行到达的事务会成功插入关系记录,得到的 relation_ship 值为 1 或 2,不创建好友关系;而后到来的事务,因为重复不插入关系记录,而更新 relation_ship = 1 | 2 或者 2 | 1,总之结果都是 3,于是它会创建好友关系。
通过这种方式,解决了业务中存在的问题,主要是借助唯一索引。
[En]
In this way, the problems existing in the business are solved, mainly with the help of unique index.
Original: https://www.cnblogs.com/flowers-bloom/p/mysql45-relation-sample.html
Author: flowers-bloom
Title: MySQL45讲之用户关注案例
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/508134/
转载文章受原作者版权保护。转载请注明原作者出处!