SMOVE 是什么
SMOVE 把成员从一个集合原子地搬到另一个集合:源集合中存在该成员并成功搬走时返回 1,源集合中没有则返回 0。两个容易误解的行为是——目标集合已经有该成员时源集合仍会删除它(去重语义);操作是单命令原子完成的,不会出现「已加目标未删源」的中间状态。
基本信息
| 适用版本 | Redis 全版本 |
|---|---|
| 语法 | SMOVE source destination member |
| 返回值 | 1 移动成功;0 成员不在源集合 |
| 原子性 | 单命令跨键原子,客户端无需自行保证 |
| 目标已存在 | 仍从源删除,目标保持不变 |
| 集群限制 | 两键需在同一哈希槽,否则报 CROSSSLOT |
典型使用场景
- 状态机流转:把任务卡从「待处理」集合移到「处理中」集合
- 消息收件箱归档:把已读消息从 inbox 移到 archive
- 权限或标签调整:成员从一个标签集合转到另一个
- 去重搬运:目标集合已有该成员时天然完成去重
- 并发安全的分拣:多个消费者抢同一元素时由单命令保证原子性
示例
示例
SADD inbox:u1 m1 m2
SADD archive:u1 m2
SMOVE inbox:u1 archive:u1 m1 # 1:m1 移入 archive
SMEMBERS inbox:u1 # m2
SMOVE inbox:u1 archive:u1 m2 # 1:源删除 m2;archive 本来已有 m2,不重复计入
SMEMBERS archive:u1 # m1 m2
SMOVE inbox:u1 archive:u1 m9 # 0:m9 不在源集合里
SCARD inbox:u1 # 核对源集合剩余数量返回与行为对照
| 情况 | 返回 | 结果 |
|---|---|---|
| 成员在源、目标无 | 1 | 源删除、目标新增 |
| 成员在源、目标也有 | 1 | 源删除、目标不变(去重) |
| 成员不在源(目标有) | 0 | 两端都不变 |
| 成员不在源(目标无) | 0 | 两端都不变 |
| 集群跨槽调用 | CROSSSLOT 错误 | 命令不执行,需用哈希标签统一槽位 |
状态机流转用 SMOVE 很自然:待处理到处理中一步原子完成。如果流转过程还需要记录时间顺序或保留历史,改用 ZSet(score 记时间戳)更合适,因为集合本身不保存顺序信息。
Cluster 模式下多键命令要求两个键落在同一槽:SMOVE 的源与目标键名需要哈希标签(如 {task:99}:todo 与 {task:99}:doing)才能保证同槽,否则命令直接报错而不会部分执行。