Redis命令:HMGET

Redis HMGET 命令详细教程

HMGET 一次读取 Hash 中多个指定字段的值,返回顺序与请求顺序一致,缺失字段对应空值。它是批量读取的首选命令。

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

一、概览与语法

redis 复制代码
HMGET key field [field ...]
项目 说明
数据类型 Hash
支持版本 Redis 2.0.0 起
key Hash 的 Key
field 一个或多个字段名,不支持通配符
返回值 值数组,顺序与请求一致;缺失字段为空值
时间复杂度 O(N),N 为请求的字段数量
ACL @read、@hash、@fast
命令标记 readonly、fast

至少需要一个字段参数,不能只写 key。官方明确说明:不存在的 Key 被当作空 Hash 处理,因此对不存在的 Key 执行 HMGET 会返回一串空值,而不是空数组或错误。$TRAE_REF

二、基础示例

以下命令在测试实例的 redis-cli 中执行。文中结果是预期说明,未实际连接 Redis 运行。

redis 复制代码
DEL tutorial:{hmget}:user tutorial:{hmget}:missing
HSET tutorial:{hmget}:user name Alice city Shanghai age 30
HMGET tutorial:{hmget}:user name city
HMGET tutorial:{hmget}:user name absent age
HMGET tutorial:{hmget}:missing name age
EXISTS tutorial:{hmget}:missing

预期结果:HMGET ... name city 返回 "Alice"、"Shanghai";HMGET ... name absent age 返回 "Alice"、(nil)、"30",缺失字段在数组中占据一个位置;对缺失 Key 的 HMGET ... name age 返回两个空值;EXISTS 为 0,说明读取不会创建 Key。

数组长度始终等于请求的字段数量,这是校验结果是否错位的可靠依据。

三、顺序保证与结果解析

HMGET 与 HGETALL 的关键区别在于顺序:HMGET 严格按请求顺序返回,而 HGETALL 的字段顺序不确定。因此 HMGET 的结果可以直接与请求字段列表按下标一一对应。

python 复制代码
fields = ["name", "absent", "age"]
values = ["Alice", None, "30"]
result = dict(zip(fields, values))
print(result)   # {'name': 'Alice', 'absent': None, 'age': '30'}

这条对应关系是 HMGET 相对 HGETALL 的核心优势:不需要字段名参与传输,就能确定每个值的归属。反过来,如果请求中出现重复字段,就会得到重复的值,业务侧应先对字段列表去重。

四、空值、空字符串与错误类型

场景 行为
Key 不存在 按请求字段数返回多个空值,不创建 Key
字段不存在 该项为空值,不报错
字段值为空字符串 返回空字符串,与"字段不存在"的空值不同
字段值为 "0" 或 "false" 正常返回该文本,属于存在的值
请求中出现重复字段 该字段的值重复返回,位置一一对应
Key 是 String、List 等非 Hash 报 WRONGTYPE 错误
未提供任何字段 报语法错误
redis 复制代码
DEL tutorial:{hmget}:edge
HSET tutorial:{hmget}:edge empty "" zero 0
HMGET tutorial:{hmget}:edge empty zero absent
SET tutorial:{hmget}:wrong text
HMGET tutorial:{hmget}:wrong a

HMGET ... empty zero absent 返回空字符串、"0"、(nil) 三项,说明空字符串与空值必须区分处理。最后一条在 String 类型上报 WRONGTYPE。

五、与相近命令的区别

命令 读取范围 是否返回字段名 顺序
HGET 单个字段 否 不适用
HMGET 多个指定字段 否 与请求顺序一致
HGETALL 全部字段与值 是(交替) 不确定
HKEYS 全部字段名 是 不确定
HVALS 全部值 否 不确定

HMGET 适合"已知要读哪些字段"的场景,HGETALL 适合"需要整个对象"的场景。需要多个字段时用 HMGET 一次取回,比循环调用 HGET 更省往返;但要注意 HMGET 的字段数量越多,单次请求与回复越大。

六、TTL、原子性与并发

HMGET 是只读命令,不会刷新整个 Key 的 TTL,也不会刷新字段自身的 TTL。在 Redis 7.4 及以后,字段可以单独设置过期时间,此时已到期的字段会以空值返回,与字段从未存在表现一致,需要区分时可配合 HTTL 或 HEXISTS。

单条 HMGET 是原子的,返回的是执行瞬间的一致快照,不会出现"部分字段来自修改前、部分来自修改后"的情况。但"先 HMGET 判断,再写入"是跨命令流程,两次调用之间其他客户端可能已修改数据,需要原子条件更新时应使用 Lua 脚本或带 WATCH 的事务。

七、客户端示例

前提为已安装 redis-py 并准备好本地测试实例。

python 复制代码
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)
k = "tutorial:{hmget}:python"
try:
    r.delete(k)
    r.hset(k, mapping={"name": "Alice", "age": "30", "empty": ""})

    fields = ["name", "empty", "absent"]
    values = r.hmget(k, fields)
    print(values)                    # ['Alice', '', None]
    print(dict(zip(fields, values))) # {'name': 'Alice', 'empty': '', 'absent': None}

    print(r.hmget(k, ["a", "b"]))    # [None, None],缺失 Key 返回空值
finally:
    r.delete(k)
    r.close()

Java(Jedis)示例,返回 List:

java 复制代码
try (Jedis jedis = new Jedis("localhost", 6379)) {
    jedis.hset("tutorial:{hmget}:java", "name", "Alice");
    List<String> values = jedis.hmget("tutorial:{hmget}:java", "name", "absent");
    System.out.println(values);   // [Alice, null]
    jedis.del("tutorial:{hmget}:java");
}

八、典型场景与性能建议

典型用途:读取用户资料的部分字段、批量校验必填字段是否齐全、从缓存对象中取几个属性。当字段列表固定时,HMGET 的返回顺序稳定,代码可以按下标直接取值,无需依赖字段名。

性能上要注意:HMGET 的时间复杂度与请求字段数成正比,且回复中包含所有请求字段(包括空值)。字段数量很大时应拆分批次,避免单次请求过大。另外,若只需要判断字段是否存在,用 HEXISTS 或 HMGET 后判空都可以,但前者更明确。

九、练习、排错与总结

练习:新建 tutorial:{hmget}:exercise,写入 a=1、b=2、c=3;执行 HMGET ... a c x,预期返回 "1"、"3"、(nil);执行 HMGET ... b b,观察重复字段会返回两个相同的值;用 HLEN 确认 Key 仍为 3 个字段,说明读取不改变数据。

排错要点:结果为空值时用 HEXISTS 区分字段缺失与 Key 缺失;报 WRONGTYPE 时用 TYPE 检查类型;取值错位时检查字段列表与返回值是否按下标对应;读到空字符串却走了"缺失"分支说明业务用了真值判断;unknown command 不会出现在 2.0 以上版本,应检查拼写或客户端封装方法名。清理使用 DEL tutorial:{hmget}:user tutorial:{hmget}:missing tutorial:{hmget}:edge tutorial:{hmget}:wrong tutorial:{hmget}:exercise。速记:批量读取指定字段、O(N) 且标记为 fast、顺序与请求一致、缺失返回空值、不创建 Key。

相关推荐
zl_dfq3 小时前
Redis 之 【常见面试题总结】(从数据类型到高可用、缓存一致性全解析)
数据库·redis
陕西企来客10 小时前
豆包检索层 9 月迭代后信源陈旧的核心 —— 缓存策略的可用性优先转向
缓存
imDwAaY13 小时前
Redis String 为什么不直接用 C 字符串?从 SDS 到三种编码
redis
imDwAaY13 小时前
Redis 的数据到底怎么存?一篇理清数据类型与底层结构
redis
谢亮_vipxieliang14 小时前
一套 Compose 搭起完整开发环境:MySQL + Redis + Nginx
redis·mysql·nginx·docker
三掌柜66615 小时前
ArkWeb 手记 07|缓存和离线页怎么做
缓存·harmonyos
wefg11 天前
【Redis】初识 Redis
数据库·redis·缓存
周之瑞1 天前
技术手记|Redis 与数据库事务不在一个世界:afterCommit、显式补偿还是 Canal?
redis
hacker_LeeFei1 天前
Windows 下配置 Redis 8.10.2 开机自启:一次踩坑全记录
数据库·windows·redis