服装 网站规划方案,室内设计者联盟网站,建立网站时什么可以使用中文,关键词优化公司如何选择Set 类型
定义#xff1a;类似 Java 中的 HashSet 类#xff0c;key 是 set 的名字#xff0c;value 是集合中的值特点 无序元素唯一查找速度快支持交集、并集、补集功能
常见命令
命令功能SADD key member …添加元素SREM key member …删除元素SCARD key获取元素个数SI…Set 类型
定义类似 Java 中的 HashSet 类key 是 set 的名字value 是集合中的值特点 无序元素唯一查找速度快支持交集、并集、补集功能
常见命令
命令功能SADD key member …添加元素SREM key member …删除元素SCARD key获取元素个数SISMEMBER key member判断一个元素是否存在于 set 中SMEMBERS获取 set 中所有元素SINTER key1 key2 …求 key1 和 key2 集合的交集SDIFF key1 key2 …求 key1 和 key2 集合的差集SUNION key1 key2 ….求 key1 和 key2 集合的并集
编码方式
IntSet 编码 定义IntSet 是一个有序的整数数组结构相比哈希表占用更少的内存空间使用条件当集合中存储的所有数据都是整数并且元素数量不超过配置项 set-max-intset-entries默认值为512功能满足使用条件时 Redis 自动使用 IntSet 编码减少内存占用HTHash Table编码 定义key 存储集合的元素value 统一设置为 null因为 Set 只关心元素是否存在不需要存储值使用条件当不满足 IntSet 编码条件时Redis 会使用哈希表来存储集合功能提供快速的查找性能但需要消耗更多内存 示例
目标用户关注与取关博主查看用户与博主的共同关注注意此处代码实现涉及较多 SpringBoot 和 MybatisPlus 相关知识已默认读者有一定基础
功能点
判断当前登录用户是否已经关注当前博主当前用户关注 取关当前博主查询当前用户与当前博主的共同关注
业务方案
Set 类型Redis 功能记录当前用户关注的所有博主并且可以查看共同关注交集操作 数据结构 Set keyvalue (set)follow:userIdprefix 做出关注行为的用户 id被 key 用户关注的用户 id 集合
MySQL 功能 记录所有关注与被关注关系创建一个关注表每个条目对应一个关注关系查询是否关注select * from subscribe_table where user_id userId and follow_user_id followUserId 查询结果不为空则已关注查询关注列表select follow_user_id from subscribe_table where user_id userId 查询结果是所有 userId 关注的博主的id 数据结构 字段名功能idprimary key 自增user_id做出关注行为的用户的 IDfollow_user_id被关注的用户的 IDcreate_time创建时间
最终方案
利用 Redis Set 的快速查询某个用户是否已经关注另一个用户利用 Redis Set 的交集操作快速实现共同关注功能利用 MySQL 的 follow 表完整记录并持久化所有关注与被关注的关系使用 MySQL 存储关注关系的基础数据并使用Redis Set来提升共同关注等高频查询场景的性能
代码实现 配置文件 目标自动移除非活跃用户的关注列表下次访问时再通过 MySQL 重建缓存方案使用 LRULeast Recently Used缓存淘汰策略。当内存超出阈值时自动淘汰最久未使用的数据注意需要为 follow 缓存设置独立的 key 前缀并结合 maxmemory-policy 配置分区缓存策略避免误删其他缓存数据maxmemory-policy allkeys-lru实体类 Follow Data
TableName(follow)
public class Follow {TableId(type IdType.AUTO)private Long id;private Long userId;private Long followUserId;TableField(fill FieldFill.INSERT)private LocalDateTime createTime;
}Controller RestController
RequestMapping(/follow)
public class FollowController {Resourceprivate IFollowService followService;GetMapping(/isFollow/{followUserId})public Result isFollow(PathVariable Long followUserId) {boolean isFollow followService.isFollow(followUserId);return Result.ok(isFollow);}PostMapping(/follow/{followUserId})public Result follow(PathVariable Long followUserId) {boolean followExecuted followService.follow(followUserId, isFollow);return Result.ok(followExecuted);}GetMapping(/commons/{targetUserId})public Result followCommons(PathVariable Long targetUserId) {ListUserDTO commons followService.followCommons(targetUserId);return Result.ok(commons);}
}Service接口 public interface IFollowService extends IServiceFollow {Boolean isFollow(Long followUserId);Boolean follow(Long followUserId);ListUserDTO followCommons(Long id);
}ServiceImpl 类 Service
public class FollowServiceImpl extends ServiceImplFollowMapper, Follow implements IFollowService {Resourceprivate StringRedisTemplate stringRedisTemplate;Resourceprivate IUserService userService;Overridepublic Boolean isFollow(Long followUserId) {// 获取当前用户idLong userId UserHolder.getUser().getId();String key follow: userId;// 缓存不为空则直接查询用户关注列表if (stringRedisTemplate.hasKey(key)) {return stringRedisTemplate.opsForSet().isMember(key, followUserId.toString());}// 缓存为空时从数据库加载用户关注列表ListLong followIds baseMapper.selectFollowedIds(userId);// 没有关注的博主则缓存空对象防止缓存穿透if (followIds.isEmpty()) {stringRedisTemplate.opsForSet().add(key, null); // 缓存空对象stringRedisTemplate.expire(key, 10, TimeUnit.MINUTES); // 设置失效时间return false;}// followIds.forEach(id - stringRedisTemplate.opsForSet().add(key, id.toString()));stringRedisTemplate.opsForSet().add(key, followIds.stream().map(String::valueOf).toArray(String[]::new));stringRedisTemplate.expire(key, 60, TimeUnit.MINUTES); // 设置失效时间return stringRedisTemplate.opsForSet().isMember(key, followUserId.toString());}Overridepublic Boolean follow(Long followUserId) {Long userId UserHolder.getUser().getId();Boolean isFollowed isFollow(followUserId);Boolean success false;if (!isFollowed) {// 未关注 关注操作Follow follow new Follow();follow.setUserId(userId);follow.setFollowUserId(followUserId);success save(follow);if (success) {stringRedisTemplate.opsForSet().add(key, followUserId.toString());}} else {// 已关注 取关操作success remove(new QueryWrapperFollow().eq(user_id, userId).eq(follow_user_id, followUserId));if (success) {stringRedisTemplate.opsForSet().remove(key, followUserId.toString());}}return success;}Overridepublic ListUserDTO followCommons(Long targetUserId) {Long userId UserHolder.getUser().getId();String key1 follow: userId;String key2 follow: targetUserId;// 求交集SetString intersect stringRedisTemplate.opsForSet().intersect(key1, key2);if (intersect null || intersect.isEmpty()) {return Collections.emptyList();}// 解析idListLong ids intersect.stream().map(Long::valueOf).collect(Collectors.toList());// 查询用户ListUserDTO users userService.listByIds(ids).stream().map(user - BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());return users;}
}FollowMapper Mapper
public interface FollowMapper extends BaseMapperFollow {// 注解方式Select(select follow_user_id from follow where user_id #{userId})ListLong selectFollowedIds(Long userId);}