Redis的hash类及主要指令
文章目录
- Redis的hash类及主要指令
- 一、hash类特点
- 二、内部实现
- 三、常用命令
- 1. HSET
- 2. HGET
- 3. HMGET
- 4. HGETALL
- 5. HDEL
- 6. HEXISTS
- 7. HKEYS
- 8. HVALS
- 9. HLEN
- 10. HINCRBY
- 11. HINCRBYFLOAT
- 12. HSETNX
- 13. HSTRLEN
- 14. HRANDFIELD
- 四、小结
Redis的hash类及主要指令
一、hash类特点
- hash 是一个键值对集合,类似 Java 里的
HashMap,一个 key 下面挂着多组 field-value - 每个 field 都是唯一的,field 可以重复写,后写的值会覆盖前面的
- 适合存对象,比如用户信息、商品详情,比把对象序列化成 string 存进去方便得多——想改哪个字段直接改,不用整个拿出来再塞回去
二、内部实现
| 版本 | 编码 | 说明 |
|---|---|---|
| 7.0 之前 | ziplist(压缩列表) | field 和 value 交替存放在一块连续内存里,省空间,但读写要遍历,O(n) |
| hashtable(哈希表) | 正经的哈希表结构,读写 O(1),但内存开销大 | |
| 7.0 及之后 | listpack(紧凑列表) | 替代 ziplist 的东西,结构上更安全,解决了 ziplist 连锁更新的问题 |
| hashtable(哈希表) | 同上,大数据量时使用 |
什么时候会从 ziplist/listpack 转成 hashtable?
- field 的数量超过
hash-max-ziplist-entries(或hash-max-listpack-entries)- 某个 field 或 value 的长度超过
hash-max-ziplist-value(或hash-max-listpack-value)这两个阈值都可以在配置文件中改,默认值一般够用。简单来说就是:数据少的时候用紧凑结构省内存,数据多了自动切到哈希表保证速度。
三、常用命令
1. HSET
往 hash 里设置 field-value。可以一次设一组,也可以一次设多组。如果 field 已经存在,会覆盖旧值。
- 语法
HSET key field value [field value ...]返回值:新增的 field 数量(覆盖旧值的不算新增)
示例
redis> HSET user name "zhangsan" (integer) 1 redis> HSET user age 25 city "beijing" (integer) 2 redis> HSET user name "lisi" (integer) 0 redis> HGET user name "lisi"注意:从 Redis 4.0 开始,HSET 支持一次设置多个 field-value,在此之前只能用 HMSET 做批量设置。现在 HMSET 已经算是被废弃了,统一用 HSET 就行。
2. HGET
获取 hash 中某个 field 对应的 value。field 不存在返回 nil。
- 语法
HGET key field返回值:field 对应的 value,或者 nil
示例
redis> HSET user name "zhangsan" age 25 (integer) 2 redis> HGET user name "zhangsan" redis> HGET user gender (nil)3. HMGET
一次性获取多个 field 的值。不存在的 field 对应位置返回 nil。
- 语法
HMGET key field [field ...]返回值:按顺序返回的 value 列表
示例
redis> HSET user name "zhangsan" age 25 city "beijing" (integer) 3 redis> HMGET user name age gender 1) "zhangsan" 2) "25" 3) (nil)跟 mget 一个道理,批量操作减少了网络往返次数,性能比一个一个 hget 高。
4. HGETALL
把整个 hash 的所有 field-value 都拿出来。返回格式是 field1, value1, field2, value2 这样交替排列。
- 语法
HGETALL key返回值:field 和 value 交替的列表,key 不存在时返回空列表
示例
redis> HSET user name "zhangsan" age 25 (integer) 2 redis> HGETALL user 1) "name" 2) "zhangsan" 3) "age" 4) "25"**⚠️ 注意:**HGETALL 是一个比较"重"的命令。如果 hash 里的 field 特别多(比如几万个),一次全拿出来会阻塞 Redis,还会占大量网络带宽。这种场景下建议用 HSCAN 分批拿。
5. HDEL
删除 hash 中指定的 field。可以一次删多个。
- 语法
HDEL key field [field ...]返回值:实际删除的 field 数量(不存在的 field 不算)
示例
redis> HSET user name "zhangsan" age 25 city "beijing" (integer) 3 redis> HDEL user age city (integer) 2 redis> HDEL user gender (integer) 0 redis> HGETALL user 1) "name" 2) "zhangsan"6. HEXISTS
判断 hash 中某个 field 是否存在。这个跟 string 的 EXISTS 不一样——EXISTS 是看 key 存不存在,HEXISTS 是看 key 里面的 field 存不存在。
- 语法
HEXISTS key field返回值:1 表示存在,0 表示不存在
示例
redis> HSET user name "zhangsan" (integer) 1 redis> HEXISTS user name (integer) 1 redis> HEXISTS user age (integer) 0 redis> HEXISTS notexist name (integer) 07. HKEYS
返回 hash 中所有的 field。
- 语法
HKEYS key返回值:field 列表,key 不存在时返回空列表
示例
redis> HSET user name "zhangsan" age 25 city "beijing" (integer) 3 redis> HKEYS user 1) "name" 2) "age" 3) "city"8. HVALS
返回 hash 中所有的 value,不返回 field。
- 语法
HVALS key返回值:value 列表,key 不存在时返回空列表
示例
redis> HSET user name "zhangsan" age 25 city "beijing" (integer) 3 redis> HVALS user 1) "zhangsan" 2) "25" 3) "beijing"9. HLEN
返回 hash 中 field 的数量。
- 语法
HLEN key返回值:field 个数,key 不存在时返回 0
示例
redis> HSET user name "zhangsan" age 25 (integer) 2 redis> HLEN user (integer) 2 redis> HLEN notexist (integer) 010. HINCRBY
把 hash 中某个 field 的值加上一个整数。field 不存在就当它是 0 开始加。值不是整数就报错。
- 语法
HINCRBY key field increment返回值:加完后的值
示例
redis> HSET user age 25 (integer) 1 redis> HINCRBY user age 1 (integer) 26 redis> HINCRBY user age -5 (integer) 21 redis> HINCRBY user score 100 (integer) 100 redis> HINCRBY user name 1 (error) ERR hash value is not an integer11. HINCRBYFLOAT
跟 HINCRBY 一样,只不过加减的是浮点数。
- 语法
HINCRBYFLOAT key field increment返回值:加完后的值(字符串形式)
示例
redis> HSET product price 19.9 (integer) 1 redis> HINCRBYFLOAT product price 0.1 "20" redis> HINCRBYFLOAT product price -5.5 "14.5" redis> HINCRBYFLOAT product price 2.0e1 "34.5"12. HSETNX
只在 field 不存在的时候才设置值,存在就不动。跟 SETNX 的思路一样。
- 语法
HSETNX key field value返回值:1 表示设置了,0 表示 field 已存在没设置
示例
redis> HSET user name "zhangsan" (integer) 1 redis> HSETNX user name "lisi" (integer) 0 redis> HSETNX user age 25 (integer) 1 redis> HGET user name "zhangsan" redis> HGET user age "25"13. HSTRLEN
返回 hash 中某个 field 的 value 的字符串长度。跟 STRLEN 差不多,只不过作用域是 hash 里的 field。
- 语法
HSTRLEN key field返回值:value 的字符长度,field 或 key 不存在返回 0
示例
redis> HSET user name "zhangsan" (integer) 1 redis> HSTRLEN user name (integer) 8 redis> HSTRLEN user notexist (integer) 014. HRANDFIELD
随机返回 hash 中的 field。可以指定返回几个,还可以选择是否带 value 一起返回。
- 语法
HRANDFIELD key [count [WITHVALUES]]返回值:随机 field 的列表,带了 WITHVALUES 的话就是 field-value 交替返回
示例
redis> HSET user name "zhangsan" age 25 city "beijing" (integer) 3 redis> HRANDFIELD user "name" redis> HRANDFIELD user 2 1) "city" 2) "age" redis> HRANDFIELD user 2 WITHVALUES 1) "age" 2) "25" 3) "name" 4) "zhangsan" redis> HRANDFIELD user -2 1) "name" 2) "name"关于 count 参数:
- count 为正数时,返回的结果不会重复
- count 为负数时,返回的结果可能重复
- count 超过 field 总数时,正数只返回全部(不报错),负数补齐到 |count| 个(有重复)
四、小结
- hash 适合存对象:比 string 序列化灵活,改哪个字段就操作哪个字段,不用整体读写
- 内部编码自动切换:小数据用 listpack/ziplist 省内存,大数据自动切 hashtable,一般不用手动管
- HGETALL 要慎用:field 太多的时候会卡,大 hash 遍历用 HSCAN
- 批量操作用 HMGET/HSET:跟 string 的 mget/mset 一个道理,减少网络开销
- 计数操作用 HINCRBY:直接操作 hash 里的数值字段,不用先读出来再加,并发场景下更安全
