Redis SET NX EX 怎样避免先写后设过期
我在给短期幂等标记做缓存时,最先删掉的是“先 SET,再 EXPIRE”这段写法。两条命令之间只要发生超时、连接断开或进程退出,就可能留下没有过期时间的键。Redis 的 SET 本身已经支持 NX 和 EX,把条件写入、值和秒级 TTL 放在同一条命令里更容易维护。
SET key value NX EX 60只在 key 不存在时写入,并同时设置 60 秒过期时间。- 返回
OK表示条件写入成功;空返回通常表示NX条件没有满足,不能当成异常重试。 EX是秒,精度要求更高时使用PX;续期已有键则应重新判断是否需要XX或KEEPTTL。
先写后设过期,问题不在命令慢而在边界分开
下面这组命令看起来直观:
SET login:once:42 done # 只有在上一条成功后才设置过期时间;两条命令之间存在断点 EXPIRE login:once:42 60
它的问题不是 SET 或 EXPIRE 单独不可靠,而是“写入成功”和“过期设置”不再属于同一个命令边界。客户端在第一条命令收到响应前断开、应用在第二条命令前退出,或者重试逻辑只重放了第一条命令,都可能留下一个永久键。对于幂等标记、短期锁提示或验证码状态,这个结果往往比一次写入失败更难排查。
生产代码里,我会先把目标写成一句话:只有不存在的 key 才能写入,并且成功写入必须带 TTL。这样就能直接对应到 SET 的条件和过期参数,而不是把两个动作交给调用方自行拼接。
SET NX EX 把三个约束放进一条命令
最小写法如下:
SET login:once:42 done NX EX 60 # NX 限制为“key 不存在才写”,EX 60 给成功写入附加 60 秒 TTL
NX 表示 key 不存在时才设置,EX 60 表示以秒设置过期时间。条件、值和生命周期参数都属于这条 SET 命令的语法,调用方不需要再补一条 EXPIRE。Redis 官方文档还提供 PX、EXAT 和 PXAT 等其他过期表达方式,但本题只需要相对秒数的 EX。

这条命令的关键价值是让“成功写入必须有过期时间”成为调用契约。它并不替你完成业务幂等设计:key 的命名、值的内容、TTL 长度和失败后的返回处理仍由应用负责。
OK、空返回和 TTL 分别说明什么
使用 NX 后,不要只判断客户端有没有抛异常,还要处理条件不满足的正常结果:
package main
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
func claimOnce(ctx context.Context, rdb *redis.Client, key string) (bool, error) {
// NX 负责只抢不存在的键,EX 让成功结果自带 60 秒生命周期。
ok, err := rdb.SetNX(ctx, key, "done", 60*time.Second).Result()
if err != nil {
// 网络或服务端错误交给上层决定是否重试,不能当成“已存在”。
return false, fmt.Errorf("set nx ex: %w", err)
}
// false 是条件未满足,不是 Redis 命令执行失败。
return ok, nil
}
上面 Go 客户端的具体方法名会随客户端版本变化,命令语义仍然对应 SET key value NX EX seconds。示例中的 time.Duration 需要补充 time 包;这里保留调用结构,重点是区分 Redis 错误与“key 已存在”。
需要观察生命周期时,再单独读取 TTL:
TTL login:once:42 # 返回剩余秒数;查询 TTL 不会改变原有过期时间
一张判断表更适合放进排障清单:
| 结果 | 含义 | 应用动作 |
|---|---|---|
OK 或客户端布尔值 true | key 不存在,写入并设置 TTL | 继续执行一次性业务 |
空返回或布尔值 false | NX 条件未满足,通常是 key 已存在 | 按已处理、重复请求或抢占失败处理 |
| 命令错误 | 参数、连接或服务端问题 | 记录真实错误,再按重试策略处理 |
TTL 为正数 | 键仍有相对过期时间 | 检查 TTL 是否符合业务预算 |

EX、PX、XX 和 KEEPTTL 不要混成一个意思
EX 使用秒,PX 使用毫秒。短期防重复场景通常先用秒表达预算,确实需要毫秒级窗口时才切换 PX,并在客户端统一时间单位,避免把 500 毫秒误写成 500 秒。
NX 是“只在不存在时设置”,适合首次占位;XX 是“只在已存在时设置”,更接近更新或续期已有键的条件。它们不是同一条业务语义的两个拼写。KEEPTTL 则表示更新值时保留已有 TTL,不等于给一个新键设置过期时间。
SET login:once:42 done NX PX 500 # 500 毫秒窗口:只对不存在的 key 写入 SET login:once:42 refreshed XX KEEPTTL # 仅更新已存在的 key,并保留原 TTL;不要把它当作首次占位
还要留意一个常见误区:SET NX EX 只解决“单条命令内的条件写入和过期参数”这一边界。它不自动延长业务流程,也不保证后续处理一定成功;如果业务需要锁续期、持有者校验或释放保护,就需要另外设计令牌和值校验,不能靠重复发送同一条 SET 代替。
发布前用四项检查确认写法没有退化
- 命令是否保留了
NX,并且 key 的命名能唯一对应一次业务尝试? - 成功写入是否在同一条
SET中携带EX或PX,没有回退成 SET 后再 EXPIRE? - 应用是否把空返回当作条件未满足,而不是把它当成 Redis 故障?
- 需要更新已有键时,是否明确选择了
XX、KEEPTTL或新的 TTL,而不是误用NX?
如果只是做一次性占位,最终可以记成一句速查:SET key value NX EX seconds。这条命令的优势不是“少写一行代码”,而是把“条件成立”和“过期时间存在”放在同一个 Redis 命令契约里。
常见问题
SET NX EX 会不会覆盖已经存在的 key?
不会。NX 条件不满足时,命令返回空结果或客户端对应的 false,原 key 不会被这次写入覆盖。
为什么还要用 TTL 命令读取剩余时间?
SET NX EX 负责设置过期时间,TTL 负责观察剩余时间。读取 TTL 不会证明业务处理已经完成,只能帮助判断键的生命周期是否还在预算内。
已有键想续期应该继续用 NX 吗?
通常不应该。NX 面向不存在键;已有键的更新应根据业务选择 XX、新 TTL 或 KEEPTTL,并额外确认是否需要持有者校验。
Redis TTL 为何返回负数
- 上一篇
- Redis TTL 为何返回负数
- 下一篇
- Redis MEMORY USAGE 怎样估算键的内存占用
-
- 数据库 · Redis | 50分钟前 |
- Redis ACL 怎样只允许消费者读取指定命令
- 207浏览 收藏
-
- 数据库 · Redis | 52分钟前 |
- Redis Pub/Sub 与 Streams 怎样按是否持久化选择
- 135浏览 收藏
-
- 数据库 · Redis | 53分钟前 | 内存 · Redis · redis 内存占用 MEMORY USAGE SAMPLES
- Redis MEMORY USAGE 怎样估算键的内存占用
- 220浏览 收藏
-
- 数据库 · Redis | 1小时前 | Redis · 集群 · Redis Cluster CROSSSLOT MGET 哈希标签
- Redis Cluster 中 MGET 为什么会遇到跨槽错误
- 143浏览 收藏
-
- 数据库 · Redis | 1小时前 |
- Redis Streams 怎样判断队列是否有积压
- 449浏览 收藏
-
- 数据库 · Redis | 1小时前 |
- Redis Function 怎样保存可复用的原子逻辑
- 286浏览 收藏
-
- 数据库 · Redis | 15小时前 |
- 事务队列 怎样区分排队错误与执行错误
- 431浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 693次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 706次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 774次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 734次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 568次使用
-
- Redis Stream XTRIM 如何避免消费组积压无限增长
- 2026-09-12 501浏览
-
- Redis AOF rewrite 期间如何判断磁盘与内存压力
- 2026-09-12 501浏览
-
- Redis RDB 和 AOF 怎么按可接受数据丢失量选择
- 2026-09-08 501浏览
-
- Redis XAUTOCLAIM 之后为什么仍有 pending:JUSTID、PEL 与消息删除边界
- 2026-08-29 501浏览
-
- Redis SET 的 GET 与 KEEPTTL 怎么一起验收:旧值返回、续期与回滚边界
- 2026-08-20 501浏览

