Redis - 集合 Set 及代码实战
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 编码,减少内存占用
HT(Hash Table)编码- 定义:key 存储集合的元素,value 统一设置为 null(因为 Set 只关心元素是否存在,不需要存储值)
- 使用条件:当不满足 IntSet 编码条件时,Redis 会使用哈希表来存储集合
- 功能:提供快速的查找性能,但需要消耗更多内存

示例
- 目标:用户关注与取关博主,查看用户与博主的共同关注
- 注意:此处代码实现涉及较多 SpringBoot 和 MybatisPlus 相关知识,已默认读者有一定基础
功能点
- 判断当前登录用户是否已经关注当前博主
- 当前用户关注 & 取关当前博主
- 查询当前用户与当前博主的共同关注
业务方案
Set 类型(Redis)
-
功能:记录当前用户关注的所有博主,并且可以查看共同关注(交集操作) -
数据结构:Setkey value (set) follow:userId(prefix + 做出关注行为的用户 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)
-
数据结构字段名 功能 id primary key (自增) user_id 做出关注行为的用户的 ID follow_user_id 被关注的用户的 ID create_time 创建时间
最终方案
- 利用 Redis Set 的快速查询某个用户是否已经关注另一个用户
- 利用 Redis Set 的交集操作快速实现共同关注功能
- 利用 MySQL 的 follow 表完整记录并持久化所有关注与被关注的关系
- 使用 MySQL 存储关注关系的基础数据,并使用Redis Set来提升共同关注等高频查询场景的性能
代码实现
-
配置文件
- 目标:自动移除非活跃用户的关注列表,下次访问时再通过 MySQL 重建缓存
- 方案:使用 LRU(Least 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) {List<UserDTO> commons = followService.followCommons(targetUserId);return Result.ok(commons);} } -
Service接口:
public interface IFollowService extends IService<Follow> {Boolean isFollow(Long followUserId);Boolean follow(Long followUserId);List<UserDTO> followCommons(Long id); } -
ServiceImpl 类:
@Service public class FollowServiceImpl extends ServiceImpl<FollowMapper, 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());}// 缓存为空时,从数据库加载用户关注列表List<Long> 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 QueryWrapper<Follow>().eq("user_id", userId).eq("follow_user_id", followUserId));if (success) {stringRedisTemplate.opsForSet().remove(key, followUserId.toString());}}return success;}@Overridepublic List<UserDTO> followCommons(Long targetUserId) {Long userId = UserHolder.getUser().getId();String key1 = "follow:" + userId;String key2 = "follow:" + targetUserId;// 求交集Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key1, key2);if (intersect == null || intersect.isEmpty()) {return Collections.emptyList();}// 解析idList<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());// 查询用户List<UserDTO> users = userService.listByIds(ids).stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());return users;} } -
FollowMapper
@Mapper public interface FollowMapper extends BaseMapper<Follow> {// 注解方式@Select("select follow_user_id from follow where user_id = #{userId}")List<Long> selectFollowedIds(Long userId);}
相关文章:
Redis - 集合 Set 及代码实战
Set 类型 定义:类似 Java 中的 HashSet 类,key 是 set 的名字,value 是集合中的值特点 无序元素唯一查找速度快支持交集、并集、补集功能 常见命令 命令功能SADD key member …添加元素SREM key member …删除元素SCARD key获取元素个数SI…...
LabVIEW面向对象编程有什么特点?
LabVIEW面向对象编程(OOP)的特点主要体现在它如何结合传统面向对象编程(OOP)的理念与LabVIEW的图形化编程模式,提供灵活的抽象和模块化的功能。以下是LabVIEW面向对象编程的几个主要特点: 1. 类&#x…...
配置Nginx自签名SSL证书,支持HTTPS
配置Nginx自签名SSL证书的流程 生成一个SSL自签名证书客户端机器信任这个自签名证书修改RHEL服务器的Nginx配置在客户机用curl测试HTTPS 生成一个SSL自签名证书 在RHEL服务器上, 用openssl命令生成一个自签名证书 openssl genrsa -out server.key 2048 #生成一个2048位的RS…...
使用Spring Boot、VUE实现SSE长连接:跟踪文件上传和任务进度
使用Spring Boot实现SSE长连接:跟踪文件上传和任务进度 文章目录 使用Spring Boot实现SSE长连接:跟踪文件上传和任务进度什么是SSE?使用场景前端库选择安装event-source-polyfill1. 创建SSE连接2. 关闭SSE连接3. 结合Vue.js使用 使用Spring B…...
计算机网络技术基础:3.计算机网络的拓扑结构
网络拓扑结构是指用传输媒体互连各种设备的物理布局,即用什么方式把网络中的计算机等设备连接起来。将工作站、服务站等网络设备抽象为点,称为“节点”;将通信线路抽象为线,称为“链路”。由节点和链路构成的抽象结构就是网络拓扑…...
go-zero(十二)消息队列
go zero 消息队列 在微服务架构中,消息队列主要通过异步通信实现服务间的解耦,使得各个服务可以独立发展和扩展。 go-zero中使用的队列组件go-queue,是gozero官方实现的基于Kafka和Beanstalkd 的消息队列框架,我们使用kafka作为演示。 一、…...
会议通知:人工智能通识教育与实践发展暨和鲸科技AI通识课解决方案发布会
今年秋季学期起,全国多所高校面向本科生开设人工智能通识课。 当前人工智能通识课程的建设进展主要分为三种情况: 全市统筹,由某头部高校牵头建设市级人工智能通识课,以北京市、天津市为代表; 已于秋季学期按照课程…...
UDS自动化测试-Service 0x27(CAPL调用dll实现key计算)
文章目录 关联文章一、CANoe加载诊断数据库cdd、dll文件二、CAPLdiagGenerateKeyFromSeed关联文章 UDS - 深论Security Access Service 27服务-安全访问状态转换 CDD文件——CANdelaStudio Vector——CAPL语言设计 CANoe诊断测试 相信读者基于Diagnostic/ISO TP Confighratio…...
订单编号如何实现
背景 常见的订单编号是带有一些信息的,比如说创建日期例如:本案例中的订单日期 自增编号日期可以使用格式化字符串,自增则可以使用redis来实现 代码实现 redis就有自增的方法 每天的key都是不一样的,且过期时间设置为1天 // 生成…...
Vue3 大事件管理系统
Vue3 项目实战: 🆗好久没有更新blog,最近在找工作,还有准备考试,哎,😶🌫️爆炸的大环境🥲 内卷开始🌯🌯 本篇文章涉及的技术栈速通链接&#x…...
IOS通过WDA自动化中遇到的问题
IOS自动化遇到的问题 搭建WDA环境中遇到的问题1、XCode unsupport iphone xxx.2、创建Bundle Identifier出现问题:Communication with Apple failed3、创建Bundle Identifier出现问题:Automatic signing failed \Signing certificate is invalid4、创建B…...
单独测试 pyautogui 的鼠标点击功能,确保它能够在当前环境中正常工作,鼠标自动点击的录制回放功能
感谢您提供的详细日志信息。根据您的反馈,问题可能出在 pyautogui 没有正确获取鼠标焦点或无法在预期的位置执行点击操作。我们将采取以下步骤来进一步诊断和解决这个问题: 1. **确保 pyautogui 正确执行点击操作**: - 我们将添加更多的调…...
路由引入问题(双点双向路由回馈问题)
简介 总所周知,路由引入import又称路由重分发redistribute,为了解决不同路由协议进程间路由信息不互通而使用的技术,由于不同路由协议的算法、机制、开销等因素的差异,它们之间无法直接交换路由信息。因此,路由引入技…...
设计模式之 适配器模式 C# 范例
在 C# 中,适配器模式(Adapter Pattern)是一种结构型设计模式,旨在将一个类的接口转换成客户端所期待的另一个接口。适配器模式允许你将现有的类包装起来,使其能够与其他接口兼容。 适配器模式的使用场景: …...
LabVIEW实现GPS通信
目录 1、GPS通信原理 2、硬件环境部署 3、程序架构 4、前面板设计 5、程序框图设计 6、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利用LabVIEW和常用模块实现物联网系…...
[leetcode100] 543. 二叉树的直径
https://leetcode.cn/problems/diameter-of-binary-tree/description/?envTypestudy-plan-v2&envIdtop-100-liked 题目描述:给一个二叉树,返回二叉树直径最大值。直径指的是二叉树中任意一个结点到另外一个结点产生路径的长度。而长度由边来代表。…...
嵌入式学习(18)-stm32F407串口接收空闲中断+DMA
一、概述 在一些一次性接收大批量数据的引用场合,如果使用接收中断会频繁的进入接收中断影响代码的运行效率。为了解决这个问题可以使用串口的空闲中断DMA实现。 二、应用 在网上招了一些例程在STM32F407的平台上都没有跑通会出现各种异常,主要原因还…...
b站视频爬虫-词云分析
一、设置爬虫程序 # requests 请求b站视频 import jsonimport fake_useragent import requests from lxml import etreeif __name__ == __main__:# UA伪装head = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like …...
如何防止订单二次重复支付?
如何防止订单二次重复支付? 在电商平台和支付系统中,防止订单二次重复支付是一个至关重要的功能。以下是一些常见的策略和技术手段,用于确保订单支付的幂等性和一致性。 目录 唯一订单号订单状态检查数据库事务乐观锁悲观锁支付渠道状态核查…...
LeetCode 24反转链表
单链表反转:详细解析与代码实现 在数据结构的学习过程中,链表是一个非常重要且有趣的部分,而单链表的反转操作更是常考的基础知识点。今天就来和大家详细讲讲如何实现单链表的反转,并通过代码示例来加深理解呀。 题目 给定单链…...
从FAST到GAMPII:一份给GNSS新手的PPP数据下载与预处理避坑指南
从FAST到GAMPII:GNSS数据预处理全流程实战指南 1. 精密单点定位的数据基石 当你第一次打开GAMP软件准备进行北斗系统的精密单点定位分析时,是否曾被各种数据文件搞得晕头转向?观测文件(o)、导航文件(n/p)、差分码偏差(DCB)文件,…...
Wot Design Uni 文件上传组件:如何实现异步上传的强大功能
Wot Design Uni 文件上传组件:如何实现异步上传的强大功能 【免费下载链接】wot-design-uni 一个基于Vue3TS开发的uni-app组件库,提供70高质量组件,支持暗黑模式、国际化和自定义主题。 项目地址: https://gitcode.com/gh_mirrors/wo/wot-d…...
轻量级本地OCR工具SmolDocling实战指南
1. 项目概述:为什么需要一个本地运行的轻量级OCR应用?SmolDocling这个名字本身就带着点工程师式的幽默感——“smol”是“small”的网络变体,强调体积小、依赖少;“Docling”则暗指文档(document)处理的小精…...
C++ 程序内存分区
C 程序运行时,操作系统会给进程分配虚拟地址空间,在 32/64 位系统中,逻辑上划分为 代码区、全局静态区、常量区、栈区、堆区 5 个区域。下面从存储内容、管理方式、生命周期、权限、代码示例、常见坑逐一拆解。一、代码区(Text 段…...
NoFences:免费开源桌面整理神器,让Windows桌面焕然一新
NoFences:免费开源桌面整理神器,让Windows桌面焕然一新 【免费下载链接】NoFences 🚧 Open Source Stardock Fences alternative 项目地址: https://gitcode.com/gh_mirrors/no/NoFences 还在为Windows桌面上杂乱无章的图标而烦恼吗&a…...
如何用Python快速接入Taotoken并调用多模型API完成数据清洗任务
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 如何用Python快速接入Taotoken并调用多模型API完成数据清洗任务 对于需要处理客户数据的开发者而言,数据清洗与结构化是…...
Windows平台苹果USB网络共享驱动自动化部署方案
Windows平台苹果USB网络共享驱动自动化部署方案 【免费下载链接】Apple-Mobile-Drivers-Installer Powershell script to easily install Apple USB and Mobile Device Ethernet (USB Tethering) drivers on Windows! 项目地址: https://gitcode.com/gh_mirrors/ap/Apple-Mob…...
6个真正可用的开源AI生活工具:免登录、本地跑、老设备友好
1. 这不是又一篇“AI工具安利文”——而是我用掉27个周末、淘汰147个候选工具后筛出的6个真生活加速器你点开这篇文章,大概率刚被某篇标题党刷屏:什么“2024最火AI神器”“打工人必备100个AI工具”,结果点进去全是截图堆砌功能罗列一句“亲测…...
AMD Ryzen终极调优实战:SMUDebugTool免费工具完整配置指南
AMD Ryzen终极调优实战:SMUDebugTool免费工具完整配置指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https:…...
AI-Shoujo HF Patch完整安装教程:3步解锁游戏全部潜力
AI-Shoujo HF Patch完整安装教程:3步解锁游戏全部潜力 【免费下载链接】AI-HF_Patch Automatically translate, uncensor and update AI-Shoujo! 项目地址: https://gitcode.com/gh_mirrors/ai/AI-HF_Patch AI-Shoujo HF Patch是AI-Shoujo游戏玩家的必备增强…...
