玩转 Redis · Set 篇

玩转 Redis · Set 篇

环境 :Docker 容器 redis-learn(Redis 7.4.11) 本篇地位 :五大类型 4/5。一句话:自动去重、无序的集合


0. 一分钟回顾

Set 可以理解为一个"自动去重的袋子":往里面放相同的元素,Redis 只保留一份;但它不保证元素的顺序。

text 复制代码
user:1:tags → { redis, database }

Set 不是 List:

  • List 有顺序,可以按下标访问;Set 无序,不能依赖返回顺序。
  • List 允许重复元素;Set 自动去重。
  • List 擅长两端进出;Set 擅长成员判断和集合运算。

典型场景:用户标签、去重、共同好友、共同兴趣、权限集合、集合差异比较。


1. 命令全家桶

操作 命令 一句话说明
SADD key member [member ...] 添加成员,重复成员自动忽略;返回实际新增数量
SMEMBERS key 查看全部成员;顺序不固定
SISMEMBER key member 判断成员是否存在;返回 1/0
SCARD key 查看成员数量
SREM key member [member ...] 按值删除成员;返回实际删除数量
SINTER key [key ...] 求交集:多个集合共同拥有的成员
SUNION key [key ...] 求并集:多个集合全部成员去重合并
SDIFF key [key ...] 求差集:第一个集合有、后续集合没有
SRANDMEMBER key [count] 随机查看成员,不删除
SPOP key [count] 随机取出并删除成员
SMOVE source destination member 把成员从一个 Set 移动到另一个 Set
DEL key 删除整个 Set(通用命令)

2. 返回值与核心规律

  • SADD 返回实际新增成员数量,不是传入参数数量。
  • SISMEMBER 返回 1 表示存在,0 表示不存在。
  • SCARD 返回 Set 成员数量,类似 List 的 LLEN
  • SREM 返回实际删除成员数量。
  • SMOVE 返回 1 表示移动成功,0 表示源集合中没有该成员。
  • SPOP 返回被随机取出的成员;如果集合空了,最后一个成员删除后 key 自动消失。
  • SMEMBERSSINTERSUNIONSDIFF 的返回顺序都不应作为业务依据。
  • key 必须完全一致:user:2:tagsuser:2:tags: 是两个不同的 key。

3. 实操流水(真实命令 + 结果)

3.1 添加成员与自动去重:SADD

text 复制代码
127.0.0.1:6379> SADD user:1:tags redis
1
127.0.0.1:6379> SADD user:1:tags redis "database"
1

第二次传入了两个成员,但 redis 已经存在,只有 database 是新增成员,所以返回 1

3.2 查看全部成员:SMEMBERS

text 复制代码
127.0.0.1:6379> SMEMBERS user:1:tags
redis
database

集合当前有 redisdatabase。Set 无序,返回顺序不固定,不能依赖本次顺序。

3.3 判断成员与统计数量:SISMEMBER、SCARD

text 复制代码
127.0.0.1:6379> SISMEMBER user:1:tags database
1
127.0.0.1:6379> SISMEMBER user:1:tags "docker"
0
127.0.0.1:6379> SCARD user:1:tags
2

database 存在,返回 1docker 不存在,返回 0;集合共有两个成员。

3.4 按值删除:SREM

text 复制代码
127.0.0.1:6379> SREM user:1:tags "database"
1
127.0.0.1:6379> SMEMBERS user:1:tags
redis

SREM 返回 1,表示成功删除 database

3.5 集合运算:交集、并集、差集

重新创建第二个用户的标签集合:

text 复制代码
127.0.0.1:6379> SADD user:2:tags "database" "linux" "redis"
3

求两个用户共同拥有的标签:

text 复制代码
127.0.0.1:6379> SINTER user:1:tags user:2:tags
redis

求两个集合全部不重复成员:

text 复制代码
127.0.0.1:6379> SUNION user:1:tags user:2:tags
redis
database
linux

差集的方向很重要。第一次查询用户 1 独有的标签:

text 复制代码
127.0.0.1:6379> SDIFF user:1:tags user:2:tags

没有输出,表示用户 1 有、用户 2 没有的标签不存在。

反过来查询用户 2 独有的标签:

text 复制代码
127.0.0.1:6379> SDIFF user:2:tags user:1:tags
database
linux

SDIFF A B 的含义是:A 有、B 没有。

3.6 随机查看与随机取出:SRANDMEMBER、SPOP

随机查看成员:

text 复制代码
127.0.0.1:6379> SRANDMEMBER user:2:tags
redis
127.0.0.1:6379> SRANDMEMBER user:2:tags
redis
127.0.0.1:6379> SRANDMEMBER user:2:tags
linux

结果可以重复,因为 SRANDMEMBER 只查看,不删除成员。

之后使用 SPOP 随机取出并删除成员:

text 复制代码
127.0.0.1:6379> SPOP user:2:tags
database
127.0.0.1:6379> SMEMBERS user:2:tags
redis
127.0.0.1:6379> SPOP user:2:tags
redis
127.0.0.1:6379> SMEMBERS user:2:tags

第二次 SMEMBERS 没有输出,说明最后一个成员也被删除。

验证 key:

text 复制代码
127.0.0.1:6379> EXISTS user:2:tags
0

3.7 移动成员:SMOVE

重新准备两个集合:

text 复制代码
127.0.0.1:6379> SADD user:1:tags "redis" "docker"
1

这里 redis 原本已经存在,所以只新增了 docker

练习中曾误写了带末尾冒号的 key:

text 复制代码
127.0.0.1:6379> SADD user:2:tags: "docker"
1
127.0.0.1:6379> SADD user:2:tags: "linux"
1

user:2:tags: 与正确的 user:2:tags 不同,后来在正确 key 上补入 linux

text 复制代码
127.0.0.1:6379> SADD user:2:tags "linux"
1

docker 从用户 1 移到用户 2:

text 复制代码
127.0.0.1:6379> SMOVE user:1:tags user:2:tags "docker"
1
127.0.0.1:6379> SMEMBERS user:2:tags
linux
docker
127.0.0.1:6379> SMEMBERS user:1:tags
redis

SMOVE 是真正的移动,不是复制:源集合中的 docker 已消失,目标集合中出现了 docker

清理误创建的临时 key:

text 复制代码
127.0.0.1:6379> DEL user:2:tags:
1
127.0.0.1:6379> EXISTS user:2:tags:
0

这里最后的 EXISTS user:2:tags 返回 0,验证的是误创建的带末尾冒号的 key 已清理;正确的 user:2:tags 仍然存在。


4. 踩坑实录

现象 教训
把 Set 当有序数组 以为 SMEMBERS 每次顺序固定 Set 无序,不能依赖成员返回顺序
重复添加成员 SADD 传入两个值但返回 1 返回的是实际新增数量,重复成员会被忽略
差集方向弄反 SDIFF user:1:tags user:2:tags 没结果 SDIFF A B 是 A 有、B 没有
混淆 SRANDMEMBERSPOP 以为随机查看会删除 SRANDMEMBER 只看;SPOP 取出并删
key 末尾多冒号 user:2:tags: 查询不到 user:2:tags 的内容 冒号也是 key 的一部分,拼写必须完全一致
误看空集合 SMEMBERS 没输出 可能是 key 不存在或集合为空,用 EXISTS 继续确认

5. 典型场景

5.1 用户标签去重

redis 复制代码
SADD user:1:tags redis docker database
SISMEMBER user:1:tags redis
SMEMBERS user:1:tags

同一个标签多次添加也只保留一份。

5.2 共同兴趣或共同好友

redis 复制代码
SINTER user:1:tags user:2:tags

交集就是两个人共同拥有的标签或共同好友。

5.3 权限或功能集合差异

redis 复制代码
SDIFF user:2:permissions user:1:permissions

可以找出一个用户多出来的权限。

5.4 随机抽奖

redis 复制代码
SPOP lottery:participants

抽出成员并删除,适合"不重复中奖"的简单抽奖。若只想随机看看,不改变候选集合,使用 SRANDMEMBER


6. 核心记忆

Set 是自动去重、无序的集合,适合标签、去重、共同好友和集合运算。

text 复制代码
SADD          加成员并自动去重
SMEMBERS      看全部成员
SISMEMBER     判断成员是否存在
SCARD         看成员数量
SREM          按值删除
SINTER        求共同成员
SUNION        合并全部不重复成员
SDIFF         求第一个集合独有成员
SRANDMEMBER   随机看,不删除
SPOP          随机取出并删除
SMOVE         在两个集合之间移动

记忆画面:

text 复制代码
Set = 一个不允许重复、没有固定顺序的集合袋子

7. 自检清单

  • Set 和 List 在顺序、重复元素方面有什么区别?
  • SADD 返回的是传入数量还是实际新增数量?
  • SMEMBERS 的返回顺序能不能依赖?
  • SISMEMBER 返回 10 分别代表什么?
  • SCARD 统计什么?
  • SREMSPOP 的删除方式有什么区别?
  • SRANDMEMBER 会不会删除成员?
  • SINTERSUNIONSDIFF 分别是什么?
  • SDIFF A B 的方向如何理解?
  • SMOVE 是复制还是移动?
  • user:2:tagsuser:2:tags: 是同一个 key 吗?
  • Set 最后一个成员被删除后,key 会怎样?

8. 类型地图(4/5)

篇章 形状 典型用途 招牌命令 状态
📗 String 一行字的纸条 缓存、计数器 SET GET INCR
📘 Hash 小表格(字段↔值) 对象、单字段修改、购物车 HSET HGET HINCRBY
📙 List 有顺序的双向链表 消息队列、最新列表 LPUSH RPOP LRANGE
📕 Set 自动去重的无序集合 标签、去重、共同好友 SADD SINTER SMEMBERS
📓 ZSet 带分数自动排队 排行榜、优先级 ZADD ZRANGE ⬅️ 下一站
相关推荐
刘发财11 分钟前
前端2秒生成500页矢量PDF,rust真的强到没朋友
前端·javascript·rust
郑州光合科技余经理44 分钟前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
毅炼44 分钟前
Rover-Suite 开源发布:轻量服务注册中心与网关一体化方案
java·后端·系统架构·gateway
梦想平凡1 小时前
百游棋牌源代码开发搭建教程(十):隔离部署、备份恢复与双端验收
java·前端·javascript·数据库·源代码管理
yume_sibai2 小时前
06-Rust Web 开发实战(Axum 框架 + 数据库 + JWT 认证 + 中间件 + 部署)
前端·数据库·rust
Gl�ria4 小时前
Redis 高可用架构对比
数据库·redis
计算机魔术师4 小时前
特朗普上台打给黄仁勋:AI末日论是骗局,我们绝不让它发生
前端
troy1284 小时前
Python 基础语法(八):Web 后端开发、数据分析与可视化、网络爬虫、人工智能 / 大模型应用
前端·python·数据分析
计算机魔术师4 小时前
CEO说要慢下来,黑客说别做梦了——同一篇论文,两种命运
前端
kyriewen5 小时前
我花3天抓了一个幽灵bug,凶手藏在第4层
前端·javascript·程序员