type
status
date
slug
summary
tags
category
icon
password
Property
Redis hash(哈希散列)是由字符类型的 field(字段)和 value 组成的哈希映射表结构(也称散列表),它非常类似于表格结构。在 hash 类型中,field 与 value 一一对应,且不允许重复。
Redis
hash
特别适合于存储对象。一个filed/value
可以看做是表格中一条数据记录;而一个key
可以对应多条数据。例如,使用 hash 类型存储表格中的数据,这里以user
为
key
,id:1
为字段,name:Cao
为 value
:通过上述方法,就把表格中的数据存储在了内存中。Redis hash 的存储结构如下图所示:
一个 hash 类型的 key 最多可以存储 (约 40 亿个)字段/值。同时 Redis hash 会为这个 key 额外储存一些附加的管理信息,比如这个键的类型、最后一次访问这个键的时间等,所以 hash 键越来越多时,Redis 耗费在管理信息方面的内存就越多。当 hash 类型移除最后一个元素后,该存储结构就会被自动删除,其占用内存也会被系统回收。
哈希对象的编码可以是
ziplist
或者 hashtable
。ziplist
编码的哈希对象使用压缩列表作为底层实现, 每当有新的键值对要加入到哈希对象时, 程序会先将保存了键的压缩列表节点推入到压缩列表表尾, 然后再将保存了值的压缩列表节点推入到压缩列表表尾, 因此:- 保存了同一键值对的两个节点总是紧挨在一起, 保存键的节点在前, 保存值的节点在后;
- 先添加到哈希对象中的键值对会被放在压缩列表的表头方向, 而后来添加到哈希对象中的键值对会被放在压缩列表的表尾方向。
举个例子, 如果执行以下 HSET 命令, 那么服务器将创建一个列表对象作为
profile
键的值:如果
profile
键的值对象使用的是 ziplist
编码:另一方面,
hashtable
编码的哈希对象使用字典作为底层实现, 哈希对象中的每个键值对都使用一个字典键值对来保存:- 字典的每个键都是一个字符串对象, 对象中保存了键值对的键;
- 字典的每个值都是一个字符串对象, 对象中保存了键值对的值。
如果前面
profile
键创建的不是 ziplist
编码的哈希对象, 而是 hashtable
编码的哈希对象, 那么这个哈希对象:编码转换
当哈希对象可以同时满足以下两个条件时, 哈希对象使用
ziplist
编码:- 哈希对象保存的所有键值对的键和值的字符串长度都小于
64
字节;
- 哈希对象保存的键值对数量小于
512
个;
不能满足这两个条件的哈希对象需要使用
hashtable
编码。在 Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了。这两个条件的上限值是可以修改的, 具体请看配置文件中关于
hash-max-ziplist-value
选项和 hash-max-ziplist-entries
选项的说明。对于使用
ziplist
编码的列表对象来说, 当使用 ziplist
编码所需的两个条件的任意一个不能被满足时, 对象的编码转换操作就会被执行: 原本保存在压缩列表里的所有键值对都会被转移并保存到字典里面, 对象的编码也会从 ziplist
变为 hashtable
。Redis哈希命令
- HDEL:删除一个或多个哈希表字段
- HEXISTS:查看哈希表 key 中,指定的字段是否存在
- HGET:获取存储在哈希表中指定字段的值
- HGETALL:获取在哈希表中指定 key 的所有字段和值
- HINCRBY:为哈希表 key 中的指定字段的整数值加上增量 increment
- HINCRBYFLOAT:为哈希表 key 中的指定字段的浮点数值加上增量 increment
- HKEYS:获取所有哈希表中的字段
- HLEN:获取哈希表中字段的数量
- HMGET:获取所有给定字段的值
- HMSET:同时将多个 field-value (域-值)对设置到哈希表 key 中
- HSET:将哈希表 key 中的字段 field 的值设为 value
- HSETNX:只有在字段 field 不存在时,设置哈希表字段的值
- HVALS:获取哈希表中所有值
- HSCAN:迭代哈希表中的键值对
- HSTRLEN:返回哈希表 key 中,与给定域field 相关联的值的字符串长度
应用场景
缓存对象
Hash 类型的 (key,field, value) 的结构与对象的(对象id, 属性, 值)的结构相似,也可以用来存储对象。
以用户信息为例,它在关系型数据库中的结构是这样的:
可以使用如下命令,将用户对象的信息存储到 Hash 类型:
Redis Hash 存储其结构如下图:
在介绍 String 类型的应用场景时有所介绍,String + Json也是存储对象的一种方式,那么存储对象时,到底用 String + json 还是用 Hash 呢?
一般对象用 String + Json 存储,对象中某些频繁变化的属性可以考虑抽出来用 Hash 类型存储。
购物车
以用户 id 为 key,商品 id 为 field,商品数量为 value,恰好构成了购物车的3个要素,如下图所示。
涉及的命令如下:
- 添加商品:
HSET cart:{用户id} {商品id} 1
- 添加数量:
HINCRBY cart:{用户id} {商品id} 1
- 商品总数:
HLEN cart:{用户id}
- 删除商品:
HDEL cart:{用户id} {商品id}
- 获取购物车所有商品:
HGETALL cart:{用户id}
当前仅仅是将商品ID存储到了Redis 中,在回显商品具体信息的时候,还需要拿着商品 id 查询一次数据库,获取完整的商品的信息。