首页/数据/数据库速查/一次性取值模式(GETDEL / GETEX PERSIST)
Redis 命令96 条

一次性取值模式(GETDEL / GETEX PERSIST)

短信验证码、单次 token 这类「读过即废」的语义用 GETDEL 原子完成;需要续期用 GETEX,避免 GET+EXPIRE 两条命令之间的竞态。

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

一次性取值模式是什么

验证码、单次令牌这类「读过即作废」的数据,需要取出即删除的原子语义:拆成两条命令(先读再删)会在并发下出现同一凭据被使用两次的窗口。取值即删除命令把两步合成一步;需要「读的同时续期」则用取值加改过期时间的命令。

基本信息

取值即删GETDEL,Redis 6.2 起支持,返回旧值并删除键
取值并改过期GETEX,返回旧值并设置或取消过期时间
旧版本替代用 Lua 脚本把取值与删除写在一段脚本里
过期参数可选秒、毫秒、绝对时间戳与取消过期几种写法
语义要点键不存在时返回空值,不报错

典型使用场景

  • 短信与邮件验证码:校验通过后取值即删,防止同一码重复使用
  • 一次性登录令牌:换取会话后立即作废,避免重放
  • 防重复提交:用一次性标记键拦住重复点击
  • 会话滑动续期:读取会话的同时延长过期时间,减少一次往返
  • 幂等控制:处理完成前先取用一次性令牌,天然避免并发重复执行

验证码校验流程

验证码校验流程
SET sms:login:13900000000 888888 EX 300   # 写入验证码,5 分钟有效
# 校验通过后原子取出并删除,防止重放
GETDEL sms:login:13900000000               # 返回 888888,同时删除键
GET sms:login:13900000000                  # 返回空,说明已被消费
# 会话滑动续期:读取的同时延长过期时间
GETEX session:web:u88 EX 1800              # 每次访问续期 30 分钟
# 旧版本或需要更复杂判断时用 Lua
EVAL "local v = redis.call('GET', KEYS[1]); if v then redis.call('DEL', KEYS[1]) end; return v" 1 sms:login:13900000000

命令对照

方式原子性适用
取值即删单命令原子一次性凭据消费
取值加改过期单命令原子读取时续期或提前失效
先读再删两条命令非原子,有并发窗口不建议用于凭据类场景
Lua 脚本整脚本原子需要额外判断条件的场景
绝对时间戳参数容易算错单位:写成本地时间戳或误用秒与毫秒,会导致键立刻过期或永不过期。
凭据类数据一旦被并发消费两次,业务侧会出现重复登录或重复扣款,必须保证单命令原子或整脚本原子。

易错点

  • 用先读再删两条命令校验验证码:并发下同一验证码可能被使用两次
  • 续期参数单位写错:键被立即过期,用户会话莫名失效
  • 旧版本客户端不支持该命令:运行时直接报未知命令,需要降级为脚本实现
  • 取值即删后业务处理失败:凭据已消失,用户需要重新获取,要提前设计重试路径

数据来源与参考

  • Redis 官方文档: GETDEL
  • Redis 官方文档: GETEX
  • Redis 官方文档: 过期时间

相关工具

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