文章目录
- Redis的hash类及主要指令
-
- 一、hash类特点
- 二、内部实现
- 三、常用命令
-
-
- [1. HSET](#1. HSET)
- [2. HGET](#2. HGET)
- [3. HMGET](#3. HMGET)
- [4. HGETALL](#4. HGETALL)
- [5. HDEL](#5. HDEL)
- [6. HEXISTS](#6. HEXISTS)
- [7. HKEYS](#7. HKEYS)
- [8. HVALS](#8. HVALS)
- [9. HLEN](#9. HLEN)
- [10. HINCRBY](#10. HINCRBY)
- [11. HINCRBYFLOAT](#11. HINCRBYFLOAT)
- [12. HSETNX](#12. HSETNX)
- [13. HSTRLEN](#13. HSTRLEN)
- [14. HRANDFIELD](#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- "zhangsan"
- "25"
- (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- "name"
- "zhangsan"
- "age"
- "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- "name"
- "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) 0
7. HKEYS
返回 hash 中所有的 field。
-
语法
HKEYS key
-
返回值:field 列表,key 不存在时返回空列表
-
示例
redis> HSET user name "zhangsan" age 25 city "beijing"
(integer) 3
redis> HKEYS user- "name"
- "age"
- "city"
8. HVALS
返回 hash 中所有的 value,不返回 field。
-
语法
HVALS key
-
返回值:value 列表,key 不存在时返回空列表
-
示例
redis> HSET user name "zhangsan" age 25 city "beijing"
(integer) 3
redis> HVALS user- "zhangsan"
- "25"
- "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) 0
10. 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 integer
11. 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) 0
14. 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- "city"
- "age"
redis> HRANDFIELD user 2 WITHVALUES - "age"
- "25"
- "name"
- "zhangsan"
redis> HRANDFIELD user -2 - "name"
- "name"
关于 count 参数:
- count 为正数时,返回的结果不会重复
- count 为负数时,返回的结果可能重复
- count 超过 field 总数时,正数只返回全部(不报错),负数补齐到 |count| 个(有重复)
四、小结
- hash 适合存对象:比 string 序列化灵活,改哪个字段就操作哪个字段,不用整体读写
- 内部编码自动切换:小数据用 listpack/ziplist 省内存,大数据自动切 hashtable,一般不用手动管
- HGETALL 要慎用:field 太多的时候会卡,大 hash 遍历用 HSCAN
- 批量操作用 HMGET/HSET:跟 string 的 mget/mset 一个道理,减少网络开销
- 计数操作用 HINCRBY:直接操作 hash 里的数值字段,不用先读出来再加,并发场景下更安全