初识Redis · list和hash类型

目录

前言:

哈希类型

基本命令

编码方式

应用场景

列表

基本命令

编码方式

应用场景


前言:

前文我们已经介绍了string的基本使用,以及对应的基本命令,最后也是简单的理解了一下string的应用场景,比如计数统计器啊,比如作为缓存的存放常用的数据啊什么的,当然也有通过设置key的过期时间,然后整个分布式锁什么的。

以上是对string类型的简单介绍,本文我们就来介绍列表和哈希类型,老实说,不管是对于string类型来说还是hash类型来说,咱们在C++的时候就有了相应的语言基础,所以我们理解起来还是非常容易的。

即我们对于一些常用的命令咱们是不用特意去记的,因为对应的函数我们已经在语言阶段学习过了,并且如果有过源码的一定实现,这里的简直就是小case。

那么话不多说,我们直接进入主题。


哈希类型

基本命令

首先对于哈希我们已经有了一定的认识,比如在位图的时候,在实现unordered_map的时候,在各种算法题的时候我们也是都有用过的。

在Redis里面,Redis里面的哈希其实和我们平常认为的hash没有两样,但是我们还是要记住一个点就是:Redis里面的k v结构,key一定是字符串,对于value可以是多种类型,所以如果我们创建一个键值对的话可以是:key field value。

这里的field不用key的原因是因为如果都使用key的话,就容易混淆了,所以在Redis中我们把key value中的value中的键值对的写成了field。

说了这么多,不会创建对应的value也百搭,我们就来看看第一个命令:Hset

对于set来说我们已经算是老常客了,因为对于set来说我们碰到了好多,比如mset,setex,psetex,setbnx等,要不然咱也不能在Redis的第一篇就说set和get是一个多么重要且大众的命令。

对于Hset的使用:

那么这时候肯定会有聪明的同学来说,那是不是还有个命令是Hget,还真有,不过使用可不是直接使用hget key就可以了,因为对于hset还有一个功能,就是创建多个键值对,毕竟我们在前文提及到了,Redis是一种网络服务,既然是网络服务,那么我们为了减少网络开销,一定要是能一次性处理多个数据的。

所以hset还可以这么干:

这样就可以一次性创建了多个键值对了,那么我们也可以使用hget来查看,既然如果光使用hget key的话,它里面这么多键值对,你要查哪个呢?这你总得让redis知道吧?

所以真正的用法是使用hget 后面跟上key之后再跟上你想要查看键值对中的field。不过对于hget来说是没有办法一次性查看多个field的value的,这倒是有点怪了。

好了,我们现在能一次性创建多个键值对了,那如果用到的时候,我们不知道这个field是否存在,此时就可以用到对应的命令hexists:

和hget一样的,它也只能查询一个键值对。

能创建也就能删除是不是?在哈希中我们用到的是hdel,肯定就有人问了,hdel和del的区别是什么?

他们的区别如图,也是非常形象的:

对于del来说,是直接干掉key-value,对于hdel来说,是干掉key-value中value中的field-value。

那么删除的时候,你可就要小心了。

好了,如果使用hexists查看的话,一个一个的查看实在是太麻烦了,我们能不能一次性直接查看完呢?当然是可以的:

即使用的命令是hkeys,就能查看key-value中的所有的field了。不过这个命令的时间复杂度是O(N),你别一看是O(N)你就又害怕了,这个N并不是Redis中所有键值对的key,它明显是key-value中的field-value的数量。

所以到了这里我们已经可以清楚在Redis中时间复杂度是O(N)的话,这个N大多数都是当前命令中key的个数,如果是所有的key,那可太可怕了,咱们一般也不会用~比如keys *之类的。

但是实际上hkeys的可怕程度也是不亚于keys *的,因为如果有的时候我们不清楚有多少的field-value的话,也是容易让Redis阻塞住的。不过现在使用没事,我们之后在生产环境中是万万不敢轻易使用的。

不过既然都有hkeys了,我们再来一个hvals也不过分吧?

既然咱们有了能查key的,也有了能查val的,我们再来个能查全部的也不过分吧?命令为:
hgetall

这里我们可以发现它的顺序也是一一对应的,比如f2下一个就是222,两两配对的。

然后这里我们简单了解两条命令,分别为hmset和hmget,hmset命令相对来说比较冗余了,因为hmset无非就能一次性设置多个键值对,但是这个操作hset可以做呀,但是对于hmget来说相对来说就好了,因为它能一次查询多个的value,和hget不同。

不过我们这里要注意一个点,我们在Redis中最讲究的是效率,既然讲究效率,那么对于hgetall,hkeys,hvals都是有一定风险的,因为键值对一旦太多了,Redis阻塞住了,效率直线下降不说,系统崩溃了可就惨了。

那么有没有我们能够在查询之前看看有多少哈希键值对个数的命令呢?有的兄弟有的:

hlen用来查看有多少的哈希键值对。所以用上面的三个函数的时候,我们还是尽可能的先用hlen吧。

有意思的是,我们这里还有一些命令,和string那边的命令非常相似的:

hsetnx,hincr,hincrby,hincrbyfloat等命令,就不用博主解释了吧~~

编码方式

对于hash来说,它的编码方式一种是hashtable一种是ziplist,对于压缩来说,我们常见的压缩算法有zip,7z,gzip等,不过我们要清楚,压缩的本质是对数据重新编码,光这么说,你可能会觉得晦涩,比如aaabbbccc,假设要对这个字符串压缩,我们可以采取最粗糙的压缩算法,a3b3c3,3就代表有多少个字母。

当然了,咱也说了,这是最粗糙的,实际上的压缩算法远远不止这么简单,不过我们可以通过这个粗糙的压缩算法理解一下压缩算法也是不错的。

那么对于ziplist来说,它的初衷就是为了节省空间的,不过这实际上是一种空间换时间的做法,对于压缩之后的数据,它读取或者是使用的时候肯定是要重新转换,放回去的时候也要转换,即转化两次,相对来说肯定就慢了不少。如果数据元素多的时候,这慢的可就是雪上加霜了。

那么Redis会根据不同的情况,看实际的数据类型,来匹配相对来说最好的编码方式,这点其实在配置文件也是有相关的加载的。

不过我们没有必要专门去记,对吧~

应用场景

对于哈希来说,应用场景可以是存储用户的数据类型,当然,这个场景对于string来说也能做到,不过就需要用到json一类的东西了。相对来说麻烦一点,所以我们一般还是选择哈希。

其实从这个应用场景我们就可以看出来还是结构化数据存储的较多。


列表

基本命令

对于list来说它其实又像C++中的顺序表也像列表,它不同的点还有它支持负数下标,并且它有4个命令可以进行插入删除,即头删头插尾删尾插都涉及到了。

那么有意思的就来了,咱们可是记得栈的特点是后进先出,那么我们对list禁用尾插头删,那这个列表它不就是一个栈吗?那么我们还可以举一反三,如果这个列表我们想把它模拟成一个队列,那么同理,禁用对应的命令,不就成为了一个队列吗?

从上图,我们已经发现了对于list来说的一个端倪,它的命令好像都是分为了l和r,大多数命令中的l和r代表的都是left和right。所以对它来说,不管干啥,几乎都是成双成对的。

首先是创建,分为了lpush和rpush

对于lpush来说,就是不断的头插,对于rpush来说就是不断的尾插,它们之后的结果肯定差的有点多,对于第一种情况,最后列表是4 3 2 1,对于第二种,最后列表是1 2 3 4,那么我们用什么来查看呢?

涉及到的命令是:lrange和lindex

这里也是非常好理解的,对于lrange来说,它需要一个区间,至于这个区间是怎么构成的,就看你自己了,不管是用正数也好,负数也好,只要你能构成一个区间就行。

对于lindex来说,就需要一个索引就像,其实从这里的这个点来看就非常像C++中的vector了,居然支持下标访问,你说神奇不神奇。

那么有意思的来了,在C++中,如果发生了越界访问,就会发生未定义的行为,如果在Redis中涉及到了"越界访问"的情况,那应该怎么办呢?

咱们记住:Redis会尽它自己最大的努力给我们一个正确的结果

就像这样,给我们这个区间中有的数据,所以面对这种情况,我们常常夸赞Redis的鲁棒性是不错的

到这里,大概率同学会说,你是说list的命令都是成双成对的吗,是不是应该有rrange?不辛的是,这里的lrange的l并不是left的意思,而是list的意思,所以也就不存在rrange了。

这里我们还可以补充一个,lpushx,这里的x的意思是exist的意思,也就是如果key存在再插入,和string里面的set xx | nx是差不多的。

既然有了push,pop也是非常合理的出现了,我们直接看结果:

但是非常不幸,主播的Redis的版本是6.0.16,而在Redis6.2版本之后,才支持lpop rpop删除多个数据

我们回想基本的增删改查,是不是我们还应该能在任意的地方增加数据?此时用的命令是linsert

这里的before可以替换成after,意思也就是在element的后面插入数据了。那么问题来了,列表不像哈希,列表可以有重复的数据,如果我的列表有两个3,怎么插入呢?

可以发现,好像是只对第一个元素生效。实际上就是这样的,它不会做特殊处理,只能咱们程序员自己想办法咯。它的时间复杂度是O(N),这个N的含义不用我多说了吧~

同样,常用的还有llen查看对应的长度:

然后刚才我们删除是只使用了l/r pop,一次性只能删除一个,那么如果我们想一次性多删除,也是有办法的,但是不能为所欲为的删除,涉及到的命令是lrem

这样,从左往右,找到1就删,直到删除两个为止:

它的返回值就是删除的个数。

我们控制删除的方向,就控制中间count就行,count是正数,就从左边删除,count是负数,就从右边删除,count是0,就全部删除完

就像这样,这里的rem代表的意思就是remove。

我们也可以通过命令来保存列表中的某一段数据,涉及的命令是ltrim

用到的是下标,而下标之外的元素就全部删除了。

在这里我们捎带一提,在Redis的官方文档中,我们看到ACL那一栏,后面带了点标签,可写的,list的,slow慢的,这其实是标签,因为ACL代表的是access control list即访问控制列表,就是权限的意思了,后续程序员们可以通过配置不同的权限,来决定哪些命令是否能执行,咱们先了解了解。

我们也能通过下标设置某个数据,这其实和数组使用下标访问很像的,涉及的命令是lset

以上都是比较常用的命令,我们现在介绍两个比较特殊的命令,它们特殊就特殊在它们会阻塞,它们是blpop,brpop,其实就是lpop和rpop的另一个版本。

在介绍生产消费模型的时候,我们其实就已经对阻塞有了一个比较形象的认识了,所以这里我也不打算细讲,我们记住两个就行:如果队列为空,尝试出队列的时候就会阻塞,直到队列不为空;如果队列为满,尝试入队列的时候就会阻塞,直到队列不为满的时候解除。

在阻塞的时候,Redis是可以执行其他命令的,但是我们首先搞清楚一个问题,阻塞的时间是多久?欸~还是那句话,跟配置文件说去吧!!!这个阻塞时间在Redis6之后可以设置为小数,Redis5之前是只能整数的。

那么我们先试试:

对于非空的列表来说,它的返回值是对应的key和首先删除的元素,后面的阻塞时间我们也是可以设置的,那么我们操作空列表试试:

当列表为空的时候,直接阻塞,当我们插入数据的时候,直接就弹出,并且告诉我们阻塞的时间了。

这里我们要清楚的一点是blpop的参数是列表和timeout,所以我写个1实际上是迷惑你的,它的作用是监测两个列表,一个是key,一个是1,当谁先有数据的时候,就先删除谁的。

这就是阻塞的pop,你想想,它是不是非常像你买早饭的时候,谁有,我就去买谁的。

编码方式

对于它的编码方式来说,分为了ziplist和linkedlist和quicklist,还是那个观点,对于ziplist来说,是空间换时间的做法,而quickedlist是ziplist和linkedlist的结合。

所以quickedlist比较折中,保留了ziplist的空间节省也保留了linkedlist的效率。

同样的,它里面也是涉及了配置文件,我们是可以通过配置文件修改的。

应用场景

我们就举一个例子吧,列表为空的时候,消费者123都执行了brpop,当列表有元素的时候,正在阻塞的它们就根据谁先执行的命令,谁就获取到了列表里面的元素。

那么我们再上点强度,对于抖音来说,你看一个视频,你得接受弹幕,评论,音频,视频,图片,作者信息等各种信息,那么如果我们将这个信息一股脑的塞到一个管道里面,阻塞住了就完蛋了,如果我们采用多个列表存储,分列表消费。

我们就成功达到了解耦合的目的!!!

当然了,这么多应用场景,这个是非常经典的,还有更多的场景同学可以自行上网搜索。


感谢阅读!

相关推荐
King.6242 分钟前
数据服务化 VS 数据中台:战略演进中的价值重构
大数据·数据库·sql·oracle·重构
Elastic 中国社区官方博客3 分钟前
Elasticsearch:AI 助理 - 从通才到专才
大数据·数据库·人工智能·神经网络·elasticsearch·搜索引擎·全文检索
花千树-01025 分钟前
MySQL 数据库备份和恢复全指南
数据库·mysql
·薯条大王29 分钟前
Node.js 操作 MySQL 数据库
javascript·数据库·mysql
Java_SuSheng1 小时前
关于SQLite轻量数据库的研究
java·数据库·spring boot·sqlite·mybatis
风象南1 小时前
Redis中5种BitMap应用场景及实现
redis·后端
maomi_95262 小时前
数据库学习通期末复习二
服务器·数据库
努力努力再努力wz2 小时前
【Linux实践系列】:用c/c++制作一个简易的进程池
linux·运维·数据库·c++·c
Chandler244 小时前
一图掌握 MySQL 核心要点
数据库·mysql
CodeJourney.4 小时前
从PPT到DeepSeek开启信息可视化的全新之旅
数据库·人工智能·算法·excel·流程图