玩转 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 ⬅️ 下一站
相关推荐
爱喝麻油的小哆1 小时前
🐾 Day 5|桌面数字人-接入llm可以对话啦
前端·three.js
我叫黑大帅1 小时前
关于没有对生产者做校验的思考
前端·面试·架构
掘金者阿豪1 小时前
你的公网 IP 是专线还是动态变化的?一文讲透动态 IP 与固定 IP 的那些事
前端·后端
超超不吵吵1 小时前
Java AI转型实战(八):RAG完整链路实战
后端
FfHUCisI1 小时前
Golang Redis 分布式锁
redis·分布式·golang
invicinble1 小时前
把握理解技术文章转化为工程水平的深度理解
前端
前端炒粉1 小时前
fetch+readablestream(Streamable)流式输出
java·服务器·前端
风骏时光牛马1 小时前
AIRAG服务异常监控告警
前端