深入学习 Redis - 深挖经典数据类型之 hash

目录

前言

一、hash 类型

1.1、操作命令

hset / hget(设置 / 获取)

hexists(检查是否存在)

hdel(删除)

hkeys(获取所有 field)

hvals (获取所有的 value)

hgetall(获取所有键值对)

hmget(查询指定个 value)

hsetnx(设置值时设置参数)

hash 自增自减处理

1.2、hash 的内部编码方式

1.3、应用场景

缓存功能

什么是高内聚,低耦合?


前言


redis 中所有的 key 都是字符串,value 的类型是存在差异的,因此出现了操控不同 value 的命令,接下来,就一起来学习一下吧~

Ps1:接下来,我给出的指令都是按照 Redis 官方文档的语法格式来解析的,[ ] 相当于一个独立的单元,表示可选项(可有可无),其中 | 表示 “或者” 的意思,多个只能出现一个,[ ] 和 [ ] 之间是可以同时存在的.

Ps2:一个快速失去年终奖的小技巧 —— 清除 redis 上所有的数据 =》 FLUSHALL,这个操作可以把 redis 上所有的键值对全部带走.

一、hash 类型


1.1、操作命令

哈希表可以说是所有数据结构中最重要的,既是日常开发中最常用的,也是面试考察的重点.

Redis 自身已经是键值对结构了,但 value 实际上还是一些个键值对(哈希表)

hset / hget(设置 / 获取)

设置 hash 中指定的字段 field 和 value ,返回值是设置成功的键值对(field - value)的个数.

HSET key field value [field value ...]

获取 hash 中指定字段 field 的 value 值. 

HGET key field

 

hexists(检查是否存在)

hexists 用来 hash 中检查字段 field 是否存在,返回 1 表示存在,返回 0 表示不存在.

HEXISTS key field

hdel(删除)

hdel 用来删除 hash 中指定的字段,返回值是本次操作删除的字段个数.

HDEL key field [field ...]

Ps:del 删除的是 key,hdel 删除的是 field

hkeys(获取所有 field)

hkeys 用来获取指定 hash 的所有 field,返回值是所有的 field ,操作的时间复杂度为 O(N),此处 N 为 hash 的元素个数.

HKEYS key

深入学习 Redis - 深挖经典数据类型之 hash_第1张图片

 Ps:这个操作也是存在一定的风险的,类似与之前介绍过的 keys *,主要是咱也不知道某个 hash 中是否存在大量的 field.

hvals (获取所有的 value)

和 hkeys 相对,能够获取到  hash 中所有的 value,操作的时间复杂度也是 O(N),N 是  哈希 元素的个数,如果 哈希 非常大,也可能导致 redis 服务器阻塞.

HVALS key

hgetall(获取所有键值对)

获取指定 hash 中所有的键值对,一般不要在生产环境使用这个命令,因为你不知道这个 hash 中有多少键值对,就可能导致 redis 阻塞,最后带走你的年终奖~

HGETALL key

深入学习 Redis - 深挖经典数据类型之 hash_第2张图片

hmget(查询指定个 value)

通过 hash 可以根据指定个 field 查出相应的 value,类似于之前学习到的 mget .

HMGET key field [field ...]

深入学习 Redis - 深挖经典数据类型之 hash_第3张图片

hlen(查询个数)

用来查询 hash 的元素个数,这个操作不需要遍历,时间复杂度是 O(1).

HLEN key

深入学习 Redis - 深挖经典数据类型之 hash_第4张图片

hsetnx(设置值时设置参数)

类似于 setnx,当 hash 的 field 不存在时,才能设置成功,若存在则不行.

返回 1 表示成功,返回 0 表示失败.

HSETNX key field value

深入学习 Redis - 深挖经典数据类型之 hash_第5张图片

hash 自增自减处理

hash 这里的 value 也可以当作数字来处理:

  1. hincrby:可以加减整数.
  2. hincrbyfloat:可以加减小数.

这些命令不经常使用,因此没有提供 incr decr... 这类命令.

1.2、hash 的内部编码方式

hash 内部有两种编码方式:

  1. hashtable:最基本的哈希表(不是 java 标准库中的 HashTable),redis 内部对哈希表的实现方式和 java 中的哈希表可能不太一样,但是整体思想都是一样的;时间上复杂度O(1),但是空间上会有一定的浪费(hash 是一个数组,数组上有些位置有元素,有些位置没有元素).
  2. ziplist:压缩列表,当哈希表里的元素比较少的时候,就优化成了 ziplist 了,能够节省空间,但是读写元素的速度比较慢.

ziplist 到底时怎么压缩的?

压缩的本质就是对数据进行重新编码,不同的数据有不同的特点,结合这些特点,重新编码后,就能够缩小体积~

例如 abbcccdddd 重新编码就变成了 1a2b3c4d.

再例如,有一个文件内容是:abcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000efgh

重新编码后就是 abcd[100]efgh.

ziplist 也是同理~

什么时候使用 ziplist?什么时候使用 hashtable?

  1. 如果 hash 中的元素比较少,使用 ziplist 表示.  元素比较多的时候使用 hashtable 表示.
  2. 每个 value 值的长度都比较短的,使用 ziplist 表示.  如果某个 value 长度太长,也会转化成 hashtable.

为什么我这里没有提到像“39”这样的具体数值?

因为这些数据类型内部转化的值都是需要根据实际工作情况而定的,他们都是再 redis.conf 文件中可以配置,满足一下任意一个就会发生转化,如下:

  1. hash-max-ziplist-entries(默认 512 个):元素个数小于这个 配置值 后,转化为 ziplist.
  2. hash-max-ziplist-value(默认 64 字节):所有 field 对应的 val 值都小于这个 配置值 后,转化为 ziplist.

1.3、应用场景

缓存功能

hash 类型存储缓存相比于 string 类型就更加合适.

例如,我有以下这样一个 UserInfo 信息 

深入学习 Redis - 深挖经典数据类型之 hash_第6张图片

假设这样一个场景就是:万一只想获取其中某一个 field ,或者修改某一个 field 的 val

如果使用 json 格式来表示 UserInfo ,就需要把数据组织成如下结构

set user:1:name James
set user:1:age 23
set user:1:city Beijing

就需要把整个 json 都读出来,解析成对象,操作field ,再转化成 json 字符串,再写回去.

但如果使用 hash 的方式来表示 UserInfo 就可以使用 field 表示对象的每一个属性(数据表的每一列),此时就可以很方便的获取属性的值了,如下结构

深入学习 Redis - 深挖经典数据类型之 hash_第7张图片

这就相当于把每个用户的各个属性给聚集起来了,实现了高内聚~

什么是高内聚,低耦合?

高内聚,就是把所有关联的东西放在一起,最好能够放在指定的位置,好找~

讲个以前的故事:我小的时候有一个缺点,就是喜欢乱放东西,衣服经常会出现在很多地方,但唯独不会出现在衣柜,因此每次我要找某一个衣服的时候就很困难,因为需要把家里的各个角落都遍历一遍.

这种场景就是属于 低内聚 ~

耦合,指的是 两个模块 / 代码 之间的关联关系,关联关系越大,越容易受影响,就认为耦合越大,而我们追求的是 低耦合 ,避免 “牵一发而动全身”,某一个地方出一个 bug,影响到了其他地方

讲个以前的故事:之前,有一次我爸得了肾结石,疼的满地打滚,后来就我去住院了,把那个结石取出来了,当时我妈为了照顾我爸,就推掉了当时工作的所有任务,请假来医院全程照顾我妈.

这种场景就输入 高耦合.

另外,当时在我微信里有一个不太熟悉的朋友(指网上认识的~)后来他发了个朋友圈,也是生病住院了,但我这边是不会有任何影响的,甚至还会给他的朋友圈点个赞 ~

这种场景就属于 低耦合.

深入学习 Redis - 深挖经典数据类型之 hash_第8张图片

 

你可能感兴趣的:(Redis深度学习,哈希算法,算法)