基本命令
hset命令
设置 hash 中指定的字段(field)的值(value)
返回值:添加的字段的个数(注意是添加的个数,而不包括修改的)
hset key field value [field value ...]
hget命令
获取 hash 中指定字段的值
返回值:字段对应的值或者 nil
hget key field
hexists命令
判断 hash 中是否有指定的字段
返回值:1 表⽰存在,0 表⽰不存在
hexists key field
hdel命令
删除 hash 中指定的字段
返回值:本次操作删除的字段个数
hdel key field [field ...]
hkeys命令
获取 hash 中的所有字段
返回值:字段列表
hkeys key
hvals命令
获取 hash 中的所有的值
返回值:所有的值
hvals key
hgetall命令
获取 hash 中的所有字段以及对应的值
返回值:字段和对应的值
hgetall key
hmget命令
⼀次获取 hash 中多个字段的值
返回值:字段对应的值或者 nil
HMGET key field [field ...]
在使用 hgetall 时,如果哈希元素个数比较多,会存在阻塞 Redis 的可能。如果开发人员只需要获取部分 field,可以使用 HMGET,如果一定要获取全部 field,可以尝试使用 hscan 命令,该命令采用渐进式遍历哈希类型
hlen命令
获取 hash 中的所有字段的个数,(返回键值对的个数)
返回值:字段个数
hlen key
hsetnx命令
在字段不存在的情况下,设置 hash 中的字段和值
返回值:1 表示设置成功,0 表示失败
hsetnx key field value
hincrby命令
将 hash 中字段对应的数值添加指定的值
返回值:该字段变化之后的值
hincrby key field increment
hincrbyfloat命令
hincrby的浮点数版本
返回值:该字段变化之后的值
hincrbyfloat key field increment
内部编码
哈希的内部编码有两种:
• ziplist(压缩列表):当哈希类型元素个数小于 hash-max-ziplist-entries 配置(默认 512 个) 同时所有值都小于 hash-max-ziplist-value 配置(默认 64 字节)时,Redis 会使用 ziplist 作为哈希的内部实现,ziplist 使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比 hashtable 更加优秀。
• hashtable(哈希表):当哈希类型无法满足 ziplist 的条件时,Redis 会使用 hashtable 作为哈希 的内部实现,因为此时 ziplist 的读写效率会下降,而 hashtable 的读写时间复杂度为 O(1)。
总结:
默认设置下,通常内部编码是ziplist,当有value大于64字节时,内部编码会转换为 hashtable,或者field超过512个时,内部编码也会转换为 hashtable
使用场景
存储用户信息
结构
相比于使用 JSON 格式的字符串缓存用户信息,哈希类型变得更加直观,并且在更新操作上变得 更灵活。可以将每个用户的 id 定义为键后缀,多对 field-value 对应用户的各个属性
但是需要注意的是哈希类型和关系型数据库有两点不同之处:
• 哈希类型是稀疏的,而关系型数据库是完全结构化的,例如哈希类型每个键可以有不同的 field,而关系型数据库一旦添加新的列,所有行都要为其设置值,即使为 null
• 关系数据库可以做复杂的关系查询,而 Redis 去模拟关系型复杂查询,例如联表查询、聚合查询等基本不可能,维护成本高。
缓存方式
1.原生字符串类型⸺使用字符串类型,每个属性一个键。
set user:1:name James
set user:1:age 23
set user:1:city Beijing
优点:实现简单,针对个别属性变更也很灵活。
缺点:占用过多的键,内存占用量较大,同时用户信息在 Redis 中比较分散,缺少内聚性,所以这种方案基本没有实用性。
2.序列化字符串类型,例如 JSON 格式
set user:1 经过序列化后的用户对象字符串
优点:针对总是以整体作为操作的信息比较合适,编程也简单。同时,如果序列化方案选择合适,内存的使用效率很高。
缺点:本身序列化和反序列需要一定开销,同时如果总是操作个别属性则非常不灵活。
3.哈希类型
hmset user:1 name James age 23 city Beijing
优点:简单、直观、灵活。尤其是针对信息的局部变更或者获取操作。
缺点:需要控制哈希在 ziplist 和 hashtable 两种内部编码的转换,可能会造成内存的较大消耗。