几乎所有的主流编程语言都提供了哈希(hash)类型它们的叫法可能是哈希、字典、关联数组、映射。在redis中哈希类型是指值本身又是一个键值对结构形如 key key , value {{filed1,value1},....,{filedN,valueN}}Redis键值对和哈希类型二者的关系可以用下图来表示。1. 为什么需要 Hash在 Redis 中String类型虽然万能但如果你要存储一个“用户对象”比如{ id: 1001, name: 张三, age: 28, city: 北京 }用 String 存要么序列化成 JSON 字符串整体存取更新某个字段不方便要么拆成多个独立的 key比如user:1001:name、user:1001:age……这样 key 太多管理麻烦。这时Hash类型就派上了用场。Hash 相当于一个 String 类型的 field-value 映射表你可以把它理解为一个“对象”每个 field 是属性名value 是属性值。在 Redis 中一个 Hash 的 key 对应一个整体而这个整体内部又包含多个field-value对。2. Hash 的基本命令我们从最常用的命令开始逐步深入。2.1 HSET – 设置字段值HSET key field value [field value ...]作用给指定的 Hash 设置一个或多个字段的值。如果字段已存在会覆盖旧值。返回本次新增的字段个数不包含更新。2.2 HGET – 获取单个字段值HGET key field返回 field 对应的 value如果 field 不存在返回nil。2.3 HEXISTS – 判断字段是否存在HEXISTS key field返回 1 表示存在0 表示不存在。2.4 HDEL – 删除一个或多个字段HDEL key field [field ...]删除指定字段返回成功删除的个数。2.5 HKEYS – 获取所有字段名HKEYS key返回 Hash 中所有 field 的列表顺序不保证。2.6 HVALS – 获取所有字段值HVALS key返回 Hash 中所有 value 的列表顺序与HKEYS对应。2.7 HGETALL – 获取所有字段和值HGETALL key返回 field 和 value 交替排列的列表奇数位是 field偶数位是 value。⚠️ 注意如果 Hash 中字段非常多比如成千上万使用HGETALL可能会阻塞 Redis因为它是 O(N) 的。建议只在字段数较少时使用或使用HSCAN渐进式遍历。2.8 HMGET – 批量获取多个字段HMGET key field [field ...]返回指定字段的值列表不存在的字段返回nil。相比多次HGETHMGET能一次取多个值减少网络往返2.9 HLEN – 获取字段个数HLEN key返回 Hash 中field 的总数。2.10 HSETNX – 字段不存在时设置HSETNX key field value只在 field不存在时才设置若 field 已存在则什么都不做。返回 1 表示设置成功0 表示失败。127.0.0.1:6379 HSETNX user:1001 email zhangsanqq.com (integer) 1 # 设置成功 127.0.0.1:6379 HSETNX user:1001 email newqq.com (integer) 0 # 已存在未修改 127.0.0.1:6379 HGET user:1001 email zhangsanqq.com2.11 HINCRBY – 整数自增/自减HINCRBY key field increment将 Hash 中某个字段必须是整数增加increment可以为负数。若字段不存在会先初始化为 0再执行操作。返回操作后的新值。127.0.0.1:6379 HSET user:1001 score 100 (integer) 1 127.0.0.1:6379 HINCRBY user:1001 score 10 (integer) 110 127.0.0.1:6379 HINCRBY user:1001 score -20 (integer) 90 127.0.0.1:6379 HINCRBY user:1001 views 1 # views 不存在先初始化为0 (integer) 1非常适用于计数器比如博客阅读量、商品浏览量的场景。2.12 HINCRBYFLOAT – 浮点数自增/自减HINCRBYFLOAT key field increment与HINCRBY类似但支持浮点数。127.0.0.1:6379 HSET user:1001 balance 100.5 (integer) 1 127.0.0.1:6379 HINCRBYFLOAT user:1001 balance 0.3 100.8 127.0.0.1:6379 HINCRBYFLOAT user:1001 balance -5.2 95.63. 内部编码了解就好Redis 内部对 Hash 有两种编码方式ziplist压缩列表当字段数较少默认 512且所有值长度较短默认 64 字节时使用节省内存。hashtable哈希表当字段数较多或值较大时使用读写效率高O(1)。你可以用OBJECT ENCODING key查看当前编码这种内部实现对你来说是无感知的但了解它能帮助你理解为什么 Hash 在小对象时很省内存。4. 实战场景4.1 缓存用户信息最经典正如开头的例子用 Hash 存储用户对象每个用户一个 key字段对应属性。优点直观易于理解。可以单独更新某个属性比如修改年龄不需要整体覆盖。批量获取HMGET也很方便。4.2 购物车每个用户一个购物车 key字段是商品 ID值是购买数量。HSET cart:1001 item_123 2 HSET cart:1001 item_456 1 HINCRBY cart:1001 item_123 1 # 增加一件 HLEN cart:1001 # 购物车商品种类数 HDEL cart:1001 item_456 # 删除某商品4.3 计数器分组比如统计每种文章的每日阅读量可以用article:2025-03-21作为 key字段是文章 ID值是阅读数。用HINCRBY轻松实现自增。5. 注意事项不要滥用HGETALL如果 Hash 很大成千上万字段HGETALL会一次性返回所有数据可能导致 Redis 阻塞。建议使用HSCAN渐进式遍历或只获取部分字段HMGET。字段名和值尽量短短字段名和短值可以触发ziplist编码节省内存。但也不必过度优化可读性更重要。Hash 不适合存储太大的对象单个 Hash 最多可存储 2^32-1 个字段但若单个 value 过大比如几 MB建议用 String 序列化存储因为 Hash 对大 value 的编码效率不高。更新频繁的单个字段用HSET或HINCRBY避免整体读写。
Redis Hash 哈希类型详解:从入门到实践
发布时间:2026/6/27 23:03:11
几乎所有的主流编程语言都提供了哈希(hash)类型它们的叫法可能是哈希、字典、关联数组、映射。在redis中哈希类型是指值本身又是一个键值对结构形如 key key , value {{filed1,value1},....,{filedN,valueN}}Redis键值对和哈希类型二者的关系可以用下图来表示。1. 为什么需要 Hash在 Redis 中String类型虽然万能但如果你要存储一个“用户对象”比如{ id: 1001, name: 张三, age: 28, city: 北京 }用 String 存要么序列化成 JSON 字符串整体存取更新某个字段不方便要么拆成多个独立的 key比如user:1001:name、user:1001:age……这样 key 太多管理麻烦。这时Hash类型就派上了用场。Hash 相当于一个 String 类型的 field-value 映射表你可以把它理解为一个“对象”每个 field 是属性名value 是属性值。在 Redis 中一个 Hash 的 key 对应一个整体而这个整体内部又包含多个field-value对。2. Hash 的基本命令我们从最常用的命令开始逐步深入。2.1 HSET – 设置字段值HSET key field value [field value ...]作用给指定的 Hash 设置一个或多个字段的值。如果字段已存在会覆盖旧值。返回本次新增的字段个数不包含更新。2.2 HGET – 获取单个字段值HGET key field返回 field 对应的 value如果 field 不存在返回nil。2.3 HEXISTS – 判断字段是否存在HEXISTS key field返回 1 表示存在0 表示不存在。2.4 HDEL – 删除一个或多个字段HDEL key field [field ...]删除指定字段返回成功删除的个数。2.5 HKEYS – 获取所有字段名HKEYS key返回 Hash 中所有 field 的列表顺序不保证。2.6 HVALS – 获取所有字段值HVALS key返回 Hash 中所有 value 的列表顺序与HKEYS对应。2.7 HGETALL – 获取所有字段和值HGETALL key返回 field 和 value 交替排列的列表奇数位是 field偶数位是 value。⚠️ 注意如果 Hash 中字段非常多比如成千上万使用HGETALL可能会阻塞 Redis因为它是 O(N) 的。建议只在字段数较少时使用或使用HSCAN渐进式遍历。2.8 HMGET – 批量获取多个字段HMGET key field [field ...]返回指定字段的值列表不存在的字段返回nil。相比多次HGETHMGET能一次取多个值减少网络往返2.9 HLEN – 获取字段个数HLEN key返回 Hash 中field 的总数。2.10 HSETNX – 字段不存在时设置HSETNX key field value只在 field不存在时才设置若 field 已存在则什么都不做。返回 1 表示设置成功0 表示失败。127.0.0.1:6379 HSETNX user:1001 email zhangsanqq.com (integer) 1 # 设置成功 127.0.0.1:6379 HSETNX user:1001 email newqq.com (integer) 0 # 已存在未修改 127.0.0.1:6379 HGET user:1001 email zhangsanqq.com2.11 HINCRBY – 整数自增/自减HINCRBY key field increment将 Hash 中某个字段必须是整数增加increment可以为负数。若字段不存在会先初始化为 0再执行操作。返回操作后的新值。127.0.0.1:6379 HSET user:1001 score 100 (integer) 1 127.0.0.1:6379 HINCRBY user:1001 score 10 (integer) 110 127.0.0.1:6379 HINCRBY user:1001 score -20 (integer) 90 127.0.0.1:6379 HINCRBY user:1001 views 1 # views 不存在先初始化为0 (integer) 1非常适用于计数器比如博客阅读量、商品浏览量的场景。2.12 HINCRBYFLOAT – 浮点数自增/自减HINCRBYFLOAT key field increment与HINCRBY类似但支持浮点数。127.0.0.1:6379 HSET user:1001 balance 100.5 (integer) 1 127.0.0.1:6379 HINCRBYFLOAT user:1001 balance 0.3 100.8 127.0.0.1:6379 HINCRBYFLOAT user:1001 balance -5.2 95.63. 内部编码了解就好Redis 内部对 Hash 有两种编码方式ziplist压缩列表当字段数较少默认 512且所有值长度较短默认 64 字节时使用节省内存。hashtable哈希表当字段数较多或值较大时使用读写效率高O(1)。你可以用OBJECT ENCODING key查看当前编码这种内部实现对你来说是无感知的但了解它能帮助你理解为什么 Hash 在小对象时很省内存。4. 实战场景4.1 缓存用户信息最经典正如开头的例子用 Hash 存储用户对象每个用户一个 key字段对应属性。优点直观易于理解。可以单独更新某个属性比如修改年龄不需要整体覆盖。批量获取HMGET也很方便。4.2 购物车每个用户一个购物车 key字段是商品 ID值是购买数量。HSET cart:1001 item_123 2 HSET cart:1001 item_456 1 HINCRBY cart:1001 item_123 1 # 增加一件 HLEN cart:1001 # 购物车商品种类数 HDEL cart:1001 item_456 # 删除某商品4.3 计数器分组比如统计每种文章的每日阅读量可以用article:2025-03-21作为 key字段是文章 ID值是阅读数。用HINCRBY轻松实现自增。5. 注意事项不要滥用HGETALL如果 Hash 很大成千上万字段HGETALL会一次性返回所有数据可能导致 Redis 阻塞。建议使用HSCAN渐进式遍历或只获取部分字段HMGET。字段名和值尽量短短字段名和短值可以触发ziplist编码节省内存。但也不必过度优化可读性更重要。Hash 不适合存储太大的对象单个 Hash 最多可存储 2^32-1 个字段但若单个 value 过大比如几 MB建议用 String 序列化存储因为 Hash 对大 value 的编码效率不高。更新频繁的单个字段用HSET或HINCRBY避免整体读写。