登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  Redis

Redis EXPIRE 的 NX 和 XX 条件如何选择

来源:17golang原创

时间:2026-09-14 13:30:13 153浏览 收藏

Redis 的 EXPIRE 已经给 key 设置过期时间后,再次调用时到底该用 NX 还是 XX,关键看你要保护哪种状态:只允许第一次补 TTL,用 NX;只允许修改已有 TTL,用 XX。两者都不会创建 key,也不是 SET NX 的替代写法。

官方地址:https://redis.io/docs/latest/commands/expire/

要点速览
  • NX 检查 key 当前没有过期时间,适合补默认 TTL。
  • XX 检查 key 当前已经有过期时间,适合受控续期或调整。
  • 返回 1 才表示 TTL 写入成功;返回 0 要结合 TTL 判断原因。

先看 key 当前有没有过期时间

EXPIRE key seconds NX 的判断是“这个 key 没有过期时间吗”,不是“这个 key 存在吗”;XX 则要求它已经是带过期时间的 volatile key。key 本身不存在时,普通 EXPIRE 就无法设置 TTL,所以两种条件都会失败。

TTL 状态NXXX含义
-2失败失败key 不存在
-1成功失败key 存在但没有 TTL
正数失败成功key 已有 TTL
Redis EXPIRE NX 和 XX 对 key 当前过期状态的静态关系示意图
图1:Redis EXPIRE 条件与 key 过期状态的关系示意图;图中只表达静态判断边界,不是运行截图。

NX 适合只补一次默认 TTL

缓存写入流程常见的要求是:业务代码可以给一个新 key 设置默认有效期,但不能因为重复执行初始化逻辑,把原来剩余较短或较长的 TTL 擅自改掉。这时让 NX 把“没有 TTL”作为唯一可写条件即可。

# 准备一个已经存在、但暂时没有过期时间的缓存键
redis-cli SET cache:user:42 "v1"
# 先确认 -1 表示 key 存在但没有 TTL
redis-cli TTL cache:user:42
# 只有没有 TTL 时才补上 300 秒默认有效期
redis-cli EXPIRE cache:user:42 300 NX
# 再次补 TTL 会失败,避免覆盖已有的过期窗口
redis-cli EXPIRE cache:user:42 600 NX
OK
-1
1
0

这里第二次返回 0 并不代表 Redis 出错,而是条件没有命中。需要注意,NX 不负责保证“值也只能写一次”;如果要限制值的创建,仍要单独设计写入命令或事务边界。

XX 适合只调整已有 TTL

会话、租约或已经进入过期管理的缓存,通常不希望某个修复分支把一个持久 key 意外变成自动删除的 key。使用 XX 后,只有当前已经存在 TTL 的 key 才会接受新的秒数。

# 先创建会话键,并给它一个初始 TTL
redis-cli SET session:42 "signed-in"
redis-cli EXPIRE session:42 900
# 只有已有 TTL 时才允许把有效期调整为 1800 秒
redis-cli EXPIRE session:42 1800 XX
# 持久 key 不满足 XX,不会被意外加上 TTL
redis-cli SET profile:42 "v1"
redis-cli EXPIRE profile:42 600 XX
OK
1
1
OK
0

因此,续期接口使用 XX 时要把返回 0 当成业务分支处理:可能是 key 已过期,也可能是上游没有给它设置初始 TTL。不要无条件把失败改成普通 EXPIRE,否则排查出来的“持久 key”会被悄悄变成有生命周期的 key。

用返回值和 TTL 做反向确认

EXPIRE 成功返回整数 1,条件未命中或 key 不存在时返回 0。写入后再读一次 TTL,能把“条件失败”和“读错 key”区分开:

  • EXPIRE ... NX 返回 0,随后 TTL 为正数:原 key 已有 TTL,NX 按预期保护了它。
  • EXPIRE ... XX 返回 0,随后 TTL-1:key 存在但没有过期时间。
  • TTL 返回 -2:key 不存在,不能只把它解释成 NX/XX 选错。
  • 多个客户端会并发修改同一个 key 时,命令本身是一次 Redis 命令;但“先 TTL、再决定 EXPIRE”的两条命令不应被当成原子业务判断。
Redis EXPIRE 返回值与 TTL -1 -2 诊断信号的静态关系示意图
图2:EXPIRE 返回值、TTL 结果与条件判断的静态关系示意图;图中不代表已执行的线上结果。

最后记住两个边界:NXXXGTLT 彼此互斥;EXPIRE 的非正秒数会导致 key 被删除,而不是产生一次普通的“到期事件”。如果只是在已有 TTL 上比较新旧时长,Redis 7.0 及以上还可以考虑 GTLT,但那是“比较时长”的问题,不要和 NX/XX 混用。

相关问题

NX 能保证 key 一定存在吗?

不能。key 不存在时,EXPIRE ... NX 仍返回 0;NX 只约束过期时间是否已经存在。

XX 失败后应该自动改用普通 EXPIRE 吗?

通常不应该。先确认业务是否允许给持久 key 增加生命周期,再决定是否补 TTL;无条件降级会掩盖初始化流程的问题。

为什么 TTL 返回 -1 不能说明 key 不存在?

-1 表示 key 存在但没有过期时间;key 不存在要看 -2。这正是选择 NX 或 XX 时最有用的区分。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>