Redis 哈希(上)
哈希是一个键值对集合,适合存储对象。本课学习哈希的基本操作。
什么是哈希?
哈希类似于编程语言中的:
- Python的dict
- JavaScript的Object
- Java的HashMap
一个Redis哈希键可以存储多个字段-值对:
user:1
├─ name → "Alice"
├─ age → "25"
├─ city → "Beijing"
└─ email → "alice@example.com"
💡 优势: 哈希可以单独修改某个字段,不需要读取整个对象。内存效率也比存储JSON字符串更高。
HSET和HGET:设置和获取字段
HSET:设置单个字段
REDIS
# 设置单个字段
HSET user:1 name "Alice"
(integer) 1 # 返回新增的字段数量
# 设置多个字段
HSET user:1 age 25 city "Beijing"
(integer) 2 # 新增了2个字段
# 更新已存在的字段
HSET user:1 name "Bob"
(integer) 0 # 字段已存在,返回0
HGET:获取单个字段
REDIS
HGET user:1 name
"Alice"
HGET user:1 age
"25"
# 字段不存在
HGET user:1 notexist
(nil)
HSETNX:仅当字段不存在时设置
REDIS
# 仅当字段不存在时设置
HSETNX user:1 name "Charlie"
(integer) 0 # 字段已存在,设置失败
HSETNX user:1 phone "13800138000"
(integer) 1 # 字段不存在,设置成功
HMSET和HMGET:批量操作
HMSET:批量设置字段
REDIS
HMSET user:2 name "Bob" age 30 city "Shanghai" email "bob@example.com"
OK
⚠️ 注意: Redis 4.0.0后,HMSET已被废弃,建议使用HSET设置多个字段。
HMGET:批量获取字段
REDIS
HMGET user:2 name age city
1) "Bob"
2) "30"
3) "Shanghai"
# 包含不存在的字段
HMGET user:2 name email phone
1) "Bob"
2) "bob@example.com"
3) (nil) # phone不存在
HGETALL:获取所有字段和值
REDIS
HGETALL user:2
1) "name"
2) "Bob"
3) "age"
4) "30"
5) "city"
6) "Shanghai"
7) "email"
8) "bob@example.com"
⚠️ 注意: HGETALL返回字段和值交替的数组。如果哈希很大,会占用大量内存和网络带宽,慎用!
HKEYS和HVALS:获取所有字段名或值
HKEYS:获取所有字段名
REDIS
HKEYS user:2
1) "name"
2) "age"
3) "city"
4) "email"
HVALS:获取所有值
REDIS
HVALS user:2
1) "Bob"
2) "30"
3) "Shanghai"
4) "bob@example.com"
HEXISTS:检查字段是否存在
REDIS
HEXISTS user:2 name
(integer) 1 # 存在
HEXISTS user:2 phone
(integer) 0 # 不存在
HDEL:删除字段
REDIS
# 删除单个字段
HDEL user:2 email
(integer) 1 # 删除了1个字段
# 删除多个字段
HDEL user:2 age city
(integer) 2 # 删除了2个字段
# 删除不存在的字段
HDEL user:2 notexist
(integer) 0
HLEN:获取字段数量
REDIS
HSET user:3 name "Charlie" age 28
HLEN user:3
(integer) 2 # 有2个字段
# 键不存在
HLEN notexist
(integer) 0
HSTRLEN:获取字段值的长度
REDIS
HSET user:1 name "Alice" bio "Software Engineer"
HSTRLEN user:1 name
(integer) 5 # "Alice"长度为5
HSTRLEN user:1 bio
(integer) 17 # "Software Engineer"长度为17
哈希应用场景
场景1:存储用户信息
REDIS
# 存储用户基本信息
HSET user:1001 name "Alice" age 25 email "alice@example.com" role "admin"
# 获取用户姓名
HGET user:1001 name
# 更新用户年龄
HSET user:1001 age 26
# 获取所有用户信息
HGETALL user:1001
场景2:购物车
REDIS
# 用户1的购物车
HSET cart:user:1 product:101 2 # 商品101,数量2
HSET cart:user:1 product:102 1 # 商品102,数量1
HSET cart:user:1 product:103 5 # 商品103,数量5
# 查看购物车所有商品
HGETALL cart:user:1
# 修改商品数量
HSET cart:user:1 product:101 3
# 删除商品
HDEL cart:user:1 product:102
# 查看购物车商品数量
HLEN cart:user:1
场景3:文章元数据
REDIS
# 存储文章信息
HSET article:123 title "Redis Tutorial" author "Alice" views 1000 likes 50
# 增加阅读数(需要HINCRBY)
HINCRBY article:123 views 1
# 增加点赞数
HINCRBY article:123 likes 1
# 获取文章标题和作者
HMGET article:123 title author
场景4:商品信息缓存
REDIS
# 缓存商品详情
HSET product:2001 name "iPhone 15" price 5999 stock 100 category "phone"
# 获取商品价格
HGET product:2001 price
# 更新库存
HSET product:2001 stock 95
# 检查商品是否存在
HEXISTS product:2001 name
哈希 vs 字符串存储对象
方式1:字符串存储JSON
REDIS
SET user:1 '{"name":"Alice","age":25,"email":"alice@example.com"}'
# 获取整个对象
GET user:1
# 修改年龄:需要读取、解析、修改、序列化、写回
# 步骤多,效率低
方式2:哈希存储
REDIS
HSET user:1 name "Alice" age 25 email "alice@example.com"
# 获取单个字段
HGET user:1 name
# 修改年龄:一步完成
HSET user:1 age 26
# 获取多个字段
HMGET user:1 name age
对比总结
| 对比项 | 字符串(JSON) | 哈希 |
|---|---|---|
| 修改单个字段 | 需要读取整个对象 | 直接修改 |
| 内存占用 | 较大(JSON格式) | 较小(紧凑存储) |
| 查询单个字段 | 需要解析JSON | 直接获取 |
| 复杂嵌套对象 | ✅ 支持 | ❌ 不支持 |
| 部分更新 | ❌ 困难 | ✅ 简单 |
💡 选择建议:
- 简单对象(扁平结构):使用哈希
- 复杂对象(嵌套结构):使用字符串存储JSON
- 需要频繁修改单个字段:使用哈希
哈希编码优化
Redis会根据哈希大小自动选择编码:
| 编码类型 | 使用条件 | 说明 |
|---|---|---|
| ziplist | 字段数量 ≤ 512,值长度 ≤ 64字节 | 压缩列表,节省内存 |
| hashtable | 字段数量 > 512 或值长度 > 64字节 | 哈希表,性能更好 |
查看编码类型
REDIS
HSET small:hash field1 "value1" field2 "value2"
OBJECT ENCODING small:hash
"ziplist"
# 添加大量字段后
HSET large:hash field1 "value1" field2 "value2" ... field600 "value600"
OBJECT ENCODING large:hash
"hashtable"
ℹ️ 了解: 编码类型由Redis自动选择,可通过配置参数调整阈值。
❓ 常见问题
Q 哈希可以存储多少个字段?
A 理论上无限制(2^32 - 1),但实际受内存限制。建议单个哈希不要超过几千个字段。
Q HGETALL会影响性能吗?
A 会。如果哈希很大,HGETALL会返回大量数据,占用内存和网络带宽。建议使用HSCAN迭代获取。
Q 哈希的字段值可以是数字吗?
A 可以。Redis中所有值都是字符串,但数字字符串可以进行数值操作(HINCRBY)。
Q 如何删除整个哈希键?
A 使用DEL命令删除键,而不是HDEL删除字段:
DEL user:1。Q 哈希支持嵌套吗?
A 不支持。哈希的值只能是字符串。如需嵌套,使用字符串存储JSON。
📖 小节
- 哈希是键值对集合,适合存储对象
- HSET/HGET设置和获取单个字段
- HMSET/HMGET批量设置和获取字段
- HGETALL获取所有字段和值(慎用)
- HKEYS/HVALS获取所有字段名或值
- HEXISTS检查字段存在,HDEL删除字段,HLEN获取字段数量
- 哈希适合存储用户信息、购物车、文章元数据等
- 简单对象用哈希,复杂嵌套对象用字符串JSON
📝 作业
- 用户信息: 使用哈希存储一个用户的信息(姓名、年龄、邮箱、城市),然后获取所有信息
- 购物车: 使用哈希实现一个购物车,添加3个商品,修改1个商品数量,删除1个商品
- 字段操作: 使用HEXISTS检查某个字段是否存在,使用HLEN统计字段数量
- 对比练习: 分别用字符串JSON和哈希存储同一个对象,对比修改单个字段的步骤
下一课
下一课我们将学习 Redis 哈希(下),学习哈希的高级操作和数值计算。



