当前位置:首页 > 文章列表 > 数据库 > Redis > Redis SET NX EX 怎样避免先写后设过期

Redis SET NX EX 怎样避免先写后设过期

来源:17golang原创 2026-10-26 01:49:36 0浏览 收藏

我在给短期幂等标记做缓存时,最先删掉的是“先 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。

Redis SET NX EX 中 SET、NX、不存在条件、value、EX、秒数和 Redis key 的静态关系说明图
图1:结构说明图,展示 SET、NX、EX 与 key/value 的静态契约,不是终端截图或运行证据。

这条命令的关键价值是让“成功写入必须有过期时间”成为调用契约。它并不替你完成业务幂等设计: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 或客户端布尔值 truekey 不存在,写入并设置 TTL继续执行一次性业务
空返回或布尔值 falseNX 条件未满足,通常是 key 已存在按已处理、重复请求或抢占失败处理
命令错误参数、连接或服务端问题记录真实错误,再按重试策略处理
TTL 为正数键仍有相对过期时间检查 TTL 是否符合业务预算
Redis SET NX EX 的 OK、空返回、key 已存在、TTL 和业务分支静态判断边界说明图
图2:结果边界说明图,展示响应值、键存在状态与 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,并额外确认是否需要持有者校验。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Redis TTL 为何返回负数Redis TTL 为何返回负数
上一篇
Redis TTL 为何返回负数
Redis MEMORY USAGE 怎样估算键的内存占用
下一篇
Redis MEMORY USAGE 怎样估算键的内存占用
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    693次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    706次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    774次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    734次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    568次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码