摘要
- 本文介绍 Redis Hash 数据类型
- 本文基于
redis-7.4.7,springboot-3.5.8 - Redis官网:https://redis.io/
- Redis 命令文档:https://redis.io/docs/latest/commands/
Hash 核心详解
- Redis Hash 是一种 key → field → value 的数据结构,本质上是
bash
key -> Map<String, String>
# 说明
key:Redis 的键(只能是 String)
field:Hash 内的字段名(String)
value:字段值(String,二进制安全)
-
Hash 的核心特性
适合存储对象型数据
支持 字段级别读写
所有操作均为 原子性
内存效率优于「String + JSON」
单个 Hash 理论最大 512 MB -
Hash 的使用场景
bash
# 对象缓存
HSET user:1 name zhangsan age 20
# 电商购物车:1)以用户id为key 2)商品id为field 3)商品数量为value
HSET cart:userId commodity:1001 1 commodity:1002 5
# 分布式锁,一个命令搞不定,需要结合Lua脚本
HINCRBY lock uuid:threadId 1 # 创建锁 或 重入+1
EXPIRE lock 30 # 30 秒后自动释放锁
- Hash结构优缺点
bash
• 优点
1)同类数据聚合存储,适合表达对象模型,便于管理与维护
2)相比 string 操作消耗内存与 CPU 更小
a.当多个小字段被组织在同一个 Hash 中时,整体内存与 CPU 开销通常小于使用多个 String Key,因为Redis 对 小 Hash 使用 ziplist / listpack(紧凑结构),减少了 Key 元数据、过期字典、指针等开销
b.Hash 过大时(BigHash)优势消失
3)相比 string,减少了 Key 数量,降低元数据与过期字典的额外开销
• 缺点
1) 默认过期只能作用在 key 级别,Hash field 级别过期需 Redis 7.4+ 才支持
```bash
# user:1 这个 Hash 不会过期
HSET user:1 name "Tom" age 18
# HEXPIRE key seconds [NX|XX|GT|LT] FIELDS numfields field [field ...]
# 只有 name field 60 秒后自动删除
HEXPIRE user:1 60 FIELDS 1 name
# 同时给多个 field 设置过期时间
HEXPIRE user:1 60 FIELDS 2 name age
# 使用毫秒级过期(HPEXPIRE)
# HPEXPIRE key milliseconds [NX|XX|GT|LT] FIELDS numfields field [field ...]
HPEXPIRE user:1 60 FIELDS 2 name age
# 查看 field 剩余秒数(HTTL),-1 表示 field 永不过期,-2 表示 field 已过期
# HTTL key FIELDS numfields field [field ...]
HTTL user:1 FIELDS 1 name
# 查看毫秒级 TTL(HPTTL),-1 表示 field 永不过期,-2 表示 field 已过期
# HPTTL key FIELDS numfields field [field ...]
HPTTL user:1 FIELDS 1 name
# 移除过期时间
# HPERSIST key FIELDS numfields field [field ...]
HPERSIST user:1 FIELDS 1 name
- 在 Redis Cluster 中,不应设计超大的 Hash Key(BigHash),否则会影响迁移、扩缩容和主从复制性能。
-
生产环境建议
一个 Hash = 一个对象
field 数量建议 < 100
单 field value 建议 < 1 KB
大对象拆分为多个 Hash
避免在大 Hash 上使用 HGETALL
Hash 命令
- SpringBoot 的
RedisTemplate<K,V>.opsForHash()中 Hash 数据类型 的操作方法与 Redis 原生命令的对应关系如下:
写入 / 更新
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 设置单个 field-value | put(H key, HK hashKey, HV value) |
HSET key field value |
新增或覆盖 |
| 批量设置 field-value | putAll(H key, Map<HK,HV> m) |
HSET key field value [field value ...] |
HMSET 已废弃 |
| field 不存在时设置 | putIfAbsent(H key, HK hashKey, HV value) |
HSETNX key field value |
原子操作 |
读取
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 获取指定 field 的值 | get(H key, Object hashKey) |
HGET key field |
不存在返回 null |
| 批量获取多个 field | multiGet(H key, Collection<HK> hashKeys) |
HMGET key field [field ...] |
不存在返回 null |
| 获取所有 value | values(H key) |
HVALS key |
O(N) |
| 获取所有 field-value | entries(H key) |
HGETALL key |
生产环境慎用 |
删除 / 存在性判断
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 删除一个或多个 field | delete(H key, Object... hashKeys) |
HDEL key field [field ...] |
返回删除数量 |
| 判断 field 是否存在 | hasKey(H key, Object hashKey) |
HEXISTS key field |
--- |
计数与数值运算
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| field 整数自增 | increment(H key, HK hashKey, long delta) |
HINCRBY key field increment |
value 必须是整数 |
| field 浮点数自增 | increment(H key, HK hashKey, double delta) |
HINCRBYFLOAT key field increment |
Redis ≥ 2.6 |
| 获取 field 对应 value 长度 | lengthOfValue(H key, HK hashKey) |
HSTRLEN key field |
不存在返回 0 |
| 获取 hash 中 field 数量 | size(H key) |
HLEN key |
--- |
随机访问(Random Access)
- ⚠️ 随机访问常用于抽样、降级策略,不适合强一致业务
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 随机返回一个 field | randomKey(H key) |
HRANDFIELD key |
Redis ≥ 6.2 |
| 随机返回一个 field-value | randomEntry(H key) |
HRANDFIELD key WITHVALUES |
Redis ≥ 6.2 |
| 随机返回多个 field | randomKeys(H key, long count) |
HRANDFIELD key count |
count < 0 可重复 |
| 随机返回多个 field-value | randomEntries(H key, long count) |
HRANDFIELD key count WITHVALUES |
--- |
遍历与扫描(推荐方式)
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 获取所有 field | keys(H key) |
HKEYS key |
O(N),大 hash 慎用 |
| 游标扫描 hash | scan(H key, ScanOptions options) |
HSCAN key cursor [MATCH] [COUNT] |
推荐替代 HGETALL |
- 📌 最佳实践
- 小 hash:HGETALL
- 大 hash / 线上系统:HSCAN
Hash Field 级别过期(Redis 7.4+)
- Redis 7.4 引入 field 级 TTL,这是 Hash 的重大能力增强
- 设置过期
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 为指定 field 设置过期时间 | expire(H key, Duration timeout, Collection<HK> hashKeys) |
HEXPIRE key seconds FIELDS n field [...] |
Redis ≥ 7.4 |
| 为指定 field 设置过期时间点 | expireAt(H key, Instant expireAt, Collection<HK> hashKeys) |
HEXPIREAT key timestamp FIELDS n field [...] |
Redis ≥ 7.4 |
| 高级过期策略 | expire(H key, Expiration expiration, ExpirationOptions options, Collection<HK> hashKeys) |
HEXPIRE / HEXPIREAT |
Spring 抽象封装 |
- 移除过期时间
| 方法功能 | 方法 | Redis 原始命令 | 备注 |
|---|---|---|---|
| 移除指定 field 的过期时间 | persist(H key, Collection<HK> hashKeys) |
HPERSIST key FIELDS n field [...] |
Redis ≥ 7.4 |