Skip to content

好友关注

关注与取关

数据库设计

创建数据库表,保存关注信息

sql
create table follow
(
    id          int auto_increment
    primary key,
    userID      int null comment '用户id',
    followID    int                                 null comment '博主id',
    idDeleted   int       default 0                 null,
    createdTime timestamp default CURRENT_TIMESTAMP null,
    constraint id
    unique (id)
);

查询关注状态

java
public Boolean getFollow(Long followId) {
    String phone = UserHolder.getUser().getPhone();
    User user = userMapper.selectOne(new QueryWrapper<User>().eq("phone", phone));
    Integer userID = user.getId();
    return followMapper.exists(
        new QueryWrapper<Follow>().eq("followID", followId).eq("userID", userID)
    );
}

关注与取关

java
public Boolean setFollow(Long id) {
    String phone = UserHolder.getUser().getPhone();
    User user = userMapper
        .selectOne(new QueryWrapper<User>().eq("phone", phone));
    Integer userID = user.getId();
    boolean isFollowed = followMapper.exists(
        new QueryWrapper<Follow>()
        .eq("followID", id).eq("userID", userID)
    );
    if (isFollowed) {
        // 取关
        followMapper.delete(new QueryWrapper<Follow>()
                            .eq("followID", id).eq("userID", userID));
        return false;
    }
    // 关注
    Follow f = new Follow();
    f.setUserID(userID);
    f.setFollowID(Math.toIntExact(id));
    followMapper.insert(f);
    return true;
}

共同关注

优化关注

关注过程中,在redis维护一个set集合存放关注列表。通过set取交集的方式查询共同关注。

java
public Boolean setFollow(Long id) {
    String phone = UserHolder.getUser().getPhone();
    User user = userMapper.selectOne(new QueryWrapper<User>().eq("phone", phone));
    Integer userID = user.getId();
    boolean isFollowed = followMapper.exists(
        new QueryWrapper<Follow>().eq("followID", id).eq("userID", userID)
    );
    if (isFollowed) {
        // 取关
        followMapper.delete(new QueryWrapper<Follow>().eq("followID", id).eq("userID", userID));
        redisTemplate.opsForSet().remove("RedisSessionDemo:follow:" + userID, String.valueOf(id));
        return false;
    }
    // 关注
    Follow f = new Follow();
    f.setUserID(userID);
    f.setFollowID(Math.toIntExact(id));
    followMapper.insert(f);
    redisTemplate.opsForSet().add("RedisSessionDemo:follow:" + userID, String.valueOf(id));
    return true;
}

共同关注

java
public List<UserDTO> getCommonFollow(Long followID) {
    String phone = UserHolder.getUser().getPhone();
    User user = userMapper.selectOne(new QueryWrapper<User>().eq("phone", phone));
    Integer userID = user.getId();
    Set<String> commonIds = redisTemplate.opsForSet().intersect("RedisSessionDemo:follow:" + userID, "RedisSessionDemo:follow:" + followID);
    if (commonIds == null) {
        return null;
    }
    List<User> commonUser = userMapper.selectBatchIds(commonIds);
    ArrayList<UserDTO> results = new ArrayList<>();
    commonUser.forEach(u -> results.add(BeanUtil.copyProperties(u, UserDTO.class)));
    return results;
}

关注推送

Feed流

关注推送也叫做Feed流,直译为投喂。为用户持续的提供“沉浸式”的体验,通过无限下拉刷新获取新的信息。

Feed流实现方案

拉模式

拉模式:也叫做读扩散。

image-20240215232926781

推模式

推模式:也叫做写扩散。

image-20240215232956590

推拉结合模式

推拉结合模式:也叫做读写混合,兼具推和拉两种模式的优点。

image-20240215233032063

实现方式对比

拉模式推模式推拉结合
写比例
读比例
用户读取延迟
实现难度复杂简单很复杂
使用场景很少使用用户量少、没有大V过千万的用户量,有大V

Released under the MIT License.