Redis实现好友关注
关注与取关
数据库设计
创建数据库表,保存关注信息
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)
);
查询关注状态
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)
);
}
关注与取关
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取交集的方式查询共同关注。
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;
}
共同关注
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流实现方案
拉模式
拉模式:也叫做读扩散。
推模式
推模式:也叫做写扩散。
推拉结合模式
推拉结合模式:也叫做读写混合,兼具推和拉两种模式的优点。
实现方式对比
拉模式 | 推模式 | 推拉结合 | |
---|---|---|---|
写比例 | 低 | 高 | 中 |
读比例 | 高 | 低 | 中 |
用户读取延迟 | 高 | 低 | 低 |
实现难度 | 复杂 | 简单 | 很复杂 |
使用场景 | 很少使用 | 用户量少、没有大V | 过千万的用户量,有大V |