Redis命令:HPEXPIREAT

Redis HPEXPIREAT 命令详细教程

HPEXPIREAT 为 Hash 中一个或多个字段设置绝对到期时刻,时间以 Unix 毫秒级时间戳表示。它与 HEXPIREAT 语义相同,只是精度为毫秒。

资料合集:https://pan.quark.cn/s/10e98d308913、https://pan.quark.cn/s/f56bc69c5338

一、概览与语法

redis 复制代码
HPEXPIREAT key unix-time-milliseconds [NX | XX | GT | LT] FIELDS numfields field [field ...]
项目 说明
数据类型 Hash 的字段级过期时间
支持版本 Redis 7.4.0 起
key 一个 Hash Key
unix-time-milliseconds 绝对 Unix 时间戳,单位毫秒
条件选项 NX、XX、GT、LT 四者最多选一,互斥
FIELDS 必填关键字
numfields 字段数量,必须与后续字段参数个数一致
时间复杂度 O(N),N 为指定字段数量
ACL @write、@hash、@fast
命令标记 write、denyoom、fast

官方明确说明:过去的时间戳会立即删除该字段。$TRAE_REF

二、逐字段返回值

数值 含义
-2 该字段不存在,或整个 Key 不存在
0 指定的 NX、XX、GT、LT 条件未满足
1 过期时间已设置或更新
2 传入的是过去的 Unix 时间,字段被立即删除

官方对 2 的定义覆盖了四种命令:HEXPIRE 或 HPEXPIRE 以 0 秒/毫秒调用,HEXPIREAT 或 HPEXPIREAT 以过去的 Unix 时间调用。$TRAE_REF

三、基础示例

以下命令需要 Redis 7.4 或更新版本,在测试实例的 redis-cli 中执行。文中结果是预期说明,未实际连接 Redis 运行。官方示例使用的 1715704971000 是一个毫秒级时间戳。

redis 复制代码
DEL tutorial:{hpexpireat}:profile
HSET tutorial:{hpexpireat}:profile field1 hello field2 world
HPEXPIREAT tutorial:{hpexpireat}:profile 1715704971000 FIELDS 2 field1 field2
HPTTL tutorial:{hpexpireat}:profile FIELDS 2 field1 field2
HPEXPIRETIME tutorial:{hpexpireat}:profile FIELDS 2 field1 field2
HPEXPIREAT tutorial:{hpexpireat}:profile 1 FIELDS 1 field1
HEXISTS tutorial:{hpexpireat}:profile field1
HEXISTS tutorial:{hpexpireat}:profile field2

预期结果:HPEXPIREAT 返回 [1, 1];HPTTL 返回两个相同的毫秒值(官方示例中为 303340 这类数值,取决于执行时刻与目标时间戳的差值);HPEXPIRETIME 返回两个相同的毫秒时间戳。传入过去的时间戳 1 后返回 [2],field1 被立即删除,HEXISTS 返回 0,而 field2 仍为 1。

如果示例中的时间戳已经过去,第一次调用就会返回 [2, 2] 并删除两个字段。实际使用时请替换为未来的时间戳。

四、如何生成毫秒时间戳

毫秒时间戳由客户端生成,Redis 不提供换算命令。

bash 复制代码
date +%s%3N
python 复制代码
import time
from datetime import datetime, timedelta, timezone

now_ms = int(time.time() * 1000)
print(now_ms)                                              # 当前毫秒时间戳
print(now_ms + 60_000)                                     # 一分钟后
print(int((datetime.now(timezone.utc) + timedelta(minutes=5)).timestamp() * 1000))

常见错误是把秒级时间戳当作毫秒传入:秒级数值比毫秒小三个数量级,作为毫秒时间戳几乎必然是"过去的时间",会导致字段被立即删除。反过来,把毫秒时间戳传给 HEXPIREAT 则会得到一个极其遥远的未来时刻。换算时务必确认单位。

五、条件选项与边界情况

选项 判断条件
NX 字段当前没有过期时间时才设置
XX 字段当前已有过期时间时才设置
GT 新到期时刻严格晚于当前到期时刻时才设置
LT 新到期时刻严格早于当前到期时刻时才设置

官方说明:对于 GT 与 LT,没有过期时间的字段被视为无限大的 TTL,因此有限时间的 GT 对无 TTL 字段通常不成立,LT 会成立。$TRAE_REF

场景 行为
Key 不存在 按输入字段数返回多个 -2,不创建 Key
字段不存在 该项返回 -2
时间戳已过去 该字段被立即删除,返回 2
时间戳不是整数 报参数类型错误
Key 是 String、List 等非 Hash 报 WRONGTYPE 错误
numfields 与实际字段数不符 报语法错误

六、与相关命令的对照

命令 对象 时间表达 单位
HPEXPIRE Hash 字段 相对 毫秒
HPEXPIREAT Hash 字段 绝对 毫秒时间戳
HEXPIREAT Hash 字段 绝对 秒时间戳
PEXPIREAT 整个 Key 绝对 毫秒时间戳
HPEXPIRETIME Hash 字段 查询绝对时刻 毫秒时间戳

字段级过期与 Key 级过期相互独立,谁先到期谁先限制数据可用性。查询字段绝对到期时刻使用 HPEXPIRETIME,查询剩余时间使用 HPTTL。

七、Python 客户端示例

前提为已安装 redis-py 且服务端为 Redis 7.4 或更新版本。

python 复制代码
import time
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)
k = "tutorial:{hpexpireat}:python"
try:
    r.delete(k)
    r.hset(k, mapping={"a": "A", "b": "B"})

    fields = ["a", "b", "missing"]
    deadline_ms = int(time.time() * 1000) + 60_000
    result = r.execute_command(
        "HPEXPIREAT", k, deadline_ms, "FIELDS", len(fields), *fields
    )
    print(result)   # [1, 1, -2]

    print(r.execute_command("HPEXPIRETIME", k, "FIELDS", 2, "a", "b"))
    # [deadline_ms, deadline_ms]

    print(r.execute_command("HPEXPIREAT", k, 1, "FIELDS", 1, "a"))   # [2]
    print(r.hexists(k, "a"))   # False
finally:
    r.delete(k)
    r.close()

八、并发、重试与适用场景

绝对时间戳的明显优势是重试语义稳定:把同一请求原样重发,到期时刻不会因为重试时刻变化而延长,这一点优于相对 TTL。但重试仍可能重复执行,条件选项只按各自规则判断,不是通用幂等保证;请求超时也不代表未执行,应先查询 HPEXPIRETIME 或 HEXISTS 再决定是否重发。

单条 HPEXPIREAT 对多个字段原子执行,但"先 HSET 写值,再 HPEXPIREAT 设期限"是两条独立调用,中间可能有其他写入。需要两者一起生效时应使用经过验证的脚本或事务设计。

典型场景:与外部系统对齐的固定过期时刻、活动截止时间、定时失效的权益字段。由于毫秒时间戳依赖客户端时钟,而判定在服务端进行,两者存在偏差时实际存活时长会与预期不符,跨机房场景应统一时间源并留出余量。

九、练习、排错与总结

练习:新建 tutorial:{hpexpireat}:exercise,写入 a=1、b=2;用 Python 计算当前时间加 10 分钟的毫秒时间戳,执行 HPEXPIREAT ... <ts> FIELDS 2 a b,预期返回 [1, 1];用 HPEXPIRETIME 确认返回该时间戳;再用 1 无条件调用,预期返回 [2] 且字段被删除。

排错要点:unknown command 时确认服务端版本不低于 7.4;字段被意外立即删除时,检查传入的是秒级还是毫秒级时间戳;返回 0 检查条件选项;返回 -2 检查字段是否缺失;HPEXPIRETIME 返回 -1 表示字段永久有效。清理使用 DEL tutorial:{hpexpireat}:profile tutorial:{hpexpireat}:exercise。速记:7.4 起支持、绝对毫秒时间戳、过去时间戳立即删除、FIELDS 必填、返回 -2/0/1/2、注意单位换算。

相关推荐
码士集团小青13 分钟前
面霸篇:高频 Java 基础问题(核心卷一)
linux·服务器·数据库·redis·缓存·1024程序员节
2301_322414280418 分钟前
springboot农产品交易平台的设计与实现08055-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·spring boot·redis·mysql·tomcat·maven·mybatis
乐茵lin30 分钟前
Redis 持久化机制详解:RDB 与 AOF
redis·bootstrap·mybatis
一条泥憨鱼2 小时前
【Redis | 黑马点评】附近商铺功能源码解读
数据库·redis·缓存
舰长1153 小时前
将百万数据插入到 Redis,有哪些实现方案?
数据结构·redis·开源
bksczm5 小时前
Redis数据结构之hash
数据结构·redis·哈希算法·1024程序员节
小南家的青蛙6 小时前
Redis的资料
redis·缓存·1024程序员节
程序员塔塔喵6 小时前
【Redis进阶篇|第十四篇】redis构建全局唯一ID
redis·全局唯一id
小南家的青蛙7 小时前
华为云DCS全产品对比
redis·1024程序员节
深圳市恒星物联科技有限公司7 小时前
排水管网监测后期运维成本高吗?成本构成与控制策略分析
运维·缓存