首页/数据/数据库速查/SMOVE 原子移动成员
Redis 命令96 条

SMOVE 原子移动成员

把成员从源集合原子移到目标集合:源中存在且移动成功返回 1,源中不存在返回 0;目标已存在该成员时源仍会删除它。

数据库速查数据更新于 2026-10-13

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)才能保证同槽,否则命令直接报错而不会部分执行。

易错点

  • 以为目标已存在会返回 0:实际仍返回 1 且源成员被删除,判断逻辑会出错
  • 跨集群多键调用不做哈希标签:报 CROSSSLOT,功能整体不可用
  • 用 SMOVE 取代「先删后加」的事务补偿逻辑:单命令本身是原子的,但业务侧仍需处理返回 0 的分支
  • 把需要顺序的流转放进 Set:成员顺序不保留,时间线索丢失
  • 源集合被清空后继续依赖它存在:键被自动删除,后续 SMEMBERS 返回空数组而非报错

数据来源与参考

  • Redis 官方文档: SMOVE

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌