Redis --- 第四讲 --- 常用数据结构 --- Hash、List

一、Hash哈希类型的基本介绍。

哈希表:之前学过的所有数据结构中,最最重要的。

1、日常开发中,出场频率非常高。

2、面试中,非常重要的考点。

Redis自身已经是键值对结构了。Redis自身的键值对就是通过哈希的方式来组织的。把key这一层组织完成之后,到了value这一层,value的其中一种类型还可以是哈希。

哈希类型中的映射关系通常称为field-value,用于区分Redis整体的键值对。

Hash类型的操作命令

HSET:设置hash中指定的字段field的值value。返回值是设置成功的Hash键值对的个数。

value是一个字符串。

HGET:获取hash中指定的字段field的值value。

HEXISTS 判端hash中是否又指定的字段。返回值:1代表存在,0代表不存在

HDEL 删除hash中指定的字段,返回值:本次操作删除的字段个数。 

HKEYS 获取hash中的所有字段这个操作,现根据key找到对应的hash,O(1),然后再遍历hash ,O(N),注意!这个操作也是存在一定的风险的!类似于之前介绍过的keys*,主要是不知道某个hash中是否会存在大量的field。

HVALS 获取Hash中所有的value。和hkeys相对,能够获取到hash中所有的value。

如果哈希非常大,这个操作就可能导致redis服务器被阻塞住。

HGETALL 获取hash中的所有字段以及对应的值

两两交替显示,一个field,一个value。这个操作还是有可能造成服务器的阻塞。但是多数情况下,不需要查询所有的field,可能只查其中几个field。

HMGET 类似于之前的MGET,可以一次查询多个field。

 HMSET,一次设置多个field和value。并不需要使用,hset已经支持多个field。

上述hkeys,hvals,hgetall都是存在一定风险的,hash的元素个数太多,执行的耗时会比较长,从而阻塞redis。hscan遍历redis的hash,但是它属于渐进式遍历,敲一次命令,遍历一小部分。再敲一次,再遍历一小部分。连续执行多次,就可以完成整个的遍历过程。化整为零。

HLEN 获取hash中的所有字段的个数

HSETNX 类似于setnx,不存在的时候,才能甚至成功,存在则设置不成功。

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

HINCRBY 加减整数

HINCRBYFLOAT 加减小数

由于使用频率不算很高,redis没有提供类似于incr,decr的操作。O(1)

hash命令总结

学习Redis的过程中,会涉及到大量的命令。过两天会忘了,练习 + 多查文档就可以记住了。

hash类型内部编码

ziplist压缩列表:压缩 rar,zip,gzip这是一些具体的压缩算法。压缩的本质是针对数据进行重新编码,不同的数据,有不同的特点,结合这些特点,进行精妙的设计。重新编码之后,就能够缩小体积。事实上,这些常见的压缩算法。都是精妙设计的。ziplist也是同理。内部的数据结构也是精心设计的。表示一个普通的hash表,可能会浪费一定的空间。hash首先是一个数组,数组上有些位置有元素,有些没有元素。ziplist付出的代价,进行读写元素,速度是比较慢的。如果元素个数少,慢的并不明显,如果元素个数太多了,慢就会雪上加霜。

如果哈希表中的元素个数比较少,使用ziplist表示,元素个数比较多,使用hashtable来表示。

每个value的值长度都比较短,使用ziplist表示,如果某个value的长度太长了,也会转换成hashtable。

也可以使用 hash-max-ziplist-entries配置项默认是512个,也就是说超过512个hash field就会使用hashtable来进行编码。这个配置项就是可以写到redis.conf文件中的。

hash-max-ziplist-value配置(默认是64字节)。

Hash的使用场景

作为缓存:string也是可以作为缓存使用的。存储结构化的数据,使用hash类型更合适一些

上述场景使用string类型也能做到,就需要使用到json这样的数据格式。如果使用string的格式来表示UserInfo万一指向获取其中的某个field,或者修改某个field。就需要把整个json读出来,解析成对象,操作field,再重写转换成json字符串,再写回去。如果使用hash的方式来表UserInfo就可以使用field表示对象的每个属性。此时就可以非常方便的修改/获取任何一个属性的值了。使用hash的方式,确实读写field更直观高效,但是付出的是空间的代价。需要控制哈希再ziplist和hashtable两种内部编码的转换,可能造成内存的较大消耗。

这种方式,相当于把同一个数据的各个属性给分散开表示了。低内聚。不推荐这样做。

高内聚,低耦合。好的代码追求上面的六个字。

高内聚:把有关联的东西放在一起,最好放在指定的地方。 

低耦合:两个模块之间的关联关系,关联关系越大,越容易相互影响。认为是耦合越大。

hash类型和关系型数据库有两点不同之处

哈希类型是稀疏的,而关系型数据库是完全结构化的。

关系型数据库可以做复杂的关系查询,而Redis去模拟关系型复杂查询,例如联表查询、聚合查询等是不可能的,维护成本高。

二、List类型基本介绍

列表List相当于数组或者顺序表

约定最左侧元素下标是0,redis的下标支持负数下标。getrange。注意list内部的结果。并非是一个简单的数组,而是更接近于双端队列。

列表中的元素是有序的。有序的含义要根据上下文区分。有的时候谈到有序,指的是升序降序。有的时候,谈到的有序指的是顺序很关键。如果把元素位置颠倒,顺序调换,此时得到的新的List和之前的List是不等价的!

区分获取和删除的的区别:lindex能获取到元素的值,lrem也能返回被删除元素的值。

列表中的元素是允许重复的,像hash这样的类型,field是不能重复的。因为当前的LIst,头和尾都能高效的插入删除元素,就可以把这个List当作一个栈和队列来使用了。

Redis有一个典型的应用场景,就是作为消息队列,最早的时候,就是通过List类型。后来Redis又提供了一个stream类型。可以实现一个复杂的消息队列。

List的操作命令

lpush 将一个或多个元素头插到List中。

按照顺序,一次头插这几个元素,全部插入完毕,4是在最前面的!4 3 2 1。时间复杂度O(1),返回值是list的长度。如果key已经存在,并且key对应的value类型,不是list此时lpush就要报错。redis中所有的这些各种数据类型的操作,都是类似的效果。

lrange命令查看List中指定范围的元素。LRANGE Key start stop。此处描述的区间也是闭区间。下标支持负数。0 ,-1所有的范围。

此处的这个序号,是专门给结果集使用的序号。跟List下标没有关系。谈到下标,往往会关注,超出范围的情况。

C++中,下标超出范围,一般会认为这是一个未定义行为。 可能会导致程序奔溃。也可能会得到一个不合法的数据。还可能看起来合法,但是错误的数据,也有可能恰好得到一个符合要求的数据。Redis中的做法,是直接尽可能的获取到给定区间的元素,如果给定区间非法,比如超出下标,就会尽可能的获取对应的内容。

此处对于越界下标的访问。python中也有如此的操作。C++中的处理机制的缺点是程序员不一定能第一时间发现问题!优点:效率比较高。

lpushx 在key存在时,将一个或者多个元素从左侧放入。不存在就什么也不做。

rpush右侧插入,尾部插入。

RPUSHX 存在就插入,不存在什么也不做。

LPOP 头删。把list左侧的元素取出来。

RPOP尾删。把list右侧的元素取出来。 时间复杂度O(1)。 

LINDEX 给定下标获取对应的元素,下标非法返回的是nil,这是一个O(N)的时间复杂度。此处N指的是list中的元素的个数。

LINSERT在某个元素的之前之后插入。

返回值:插入之后,得到的新的list的长度。万一要插入的列表中,基准值存在多个怎么办

linsert进行插入的时候,要根据基准值,找到对应的位置,从左往右找,找到第一个符合基准值的位置即可。时间复杂度也是一个O(N)。N表示列表的长度。

LLEN 获取长度。

LREM rem其实就是remove的缩写。

count 要删除的个数,element,要删除的值。时间复杂度O(N+M)。

count > 0 从左往右寻找,删除count个就可以了

count < 0 从右往左寻找,删除count个就可以了

count = 0 删除所有的元素。

LTRIM 删除list中的元素。指定一个范围,保留start和stop之间区间内的元素,区间外面两边的元素就直接被删除了。

官方文档中还有这个东西,access control list 访问控制列表这是和权限相关的操作。Redis6开始支持的。都是针对6及其以上版本才有的。Redis有很多命令acl这块就把每个命令都打上一些标签,打好所有的标签之后,管理员就可以给每个redis用户配置不同的权限。允许该用户可以执行哪些标签对应的命令。这里并非是一个知识点。只不过需要用到时候要查一下配置具体怎么写。

LSET 根据下标修改元素。也是一个O(N)的时间复杂度。

lindex可以很好的处理下标越界的情况,直接返回nil,lset来说则会报错,不会像js那样,直接在10这个下标这里搞出个元素来。

阻塞版本的命令:阻塞,当前的线程不走了,代码不继续执行了。会在满足一定的条件之后,被唤醒。

BLPOP lpop 如果list中存在元素,blpop和brpop就和lpop以及rpop作用完全相同。如果list为空那么就会阻塞。

BRPOP rpop

以上两个命令相当于 lpop rpop,B =》block(阻塞)阻塞队列,多线程的时候,我们了解过了生产者消费者模型。使用队列来作为中间的交易场所。期望这个队列会有两个特性。1、线程安全,2、阻塞功能,如果队列为空尝试出队列就会产生阻塞。直到队列不空,阻塞解除,如果队列为满,尝试入队列,也会产生阻塞,直到队列不满,阻塞解除。

redis中的list也相当于阻塞队列一样,线程安全是通过单线程模型支持的。阻塞则只支持队列为空的情况。

使用brpop和blpop的时候,这里是可以显式设置阻塞时间的,不一定是无休止的等待!期间Redis可以执行其他命令,此处blpop和brpop看起来好像耗时很久,但是实际上并不会对redis服务器产生负面影响。

命令中如果设置了多个键,那么会从左向右进行遍历键,一旦有一个键对应的列表中可以弹出元素,命令立即返回。blpop和brpop都是可以同时去尝试获取多个key的列表的元素的。多个key对应多个list,这多个list哪个有元素了,就会返回哪个元素。

如果多个客户端同时对一个键执行pop,则最先执行命令的客户端会最先得到弹出的元素。

此处可以指定一个key或者多个key,每个key都对应一个list,如果这些list有一个非空,blpop都能够把这里的元素给获取到,立即返回。如果这些list都为空,此时就需要阻塞等待,等待其他客户端往这些list中插入元素了。此处还可以指定超时时间,单位是秒 Redis6 超时时间允许设定成小数,Redis5中,超时时间得是整数。

针对一个非空的列表进行操作。

返回结果相当于一个pair(二元组)一方面是告诉我们当前的数据来自于哪个key,一方面告诉我们取到的数据是啥。

针对一个空的列表,多个key进行操作:

返回结果相当于一个pair(二元组)一方面是告诉我们当前的数据来自于哪个key,一方面告诉我们取到的数据是啥。brpop和blpop的阻塞机制是完全相同的。

此处的这两个阻塞命令用途主要就是用来作为消息队列。

命令总结:

 list内部编码:

以前的编码方式

当前的编码方式

quicklist:ziplist和linkedlist的结合体。ziplist把数据按照更紧凑的压缩形式进行标识的,节省空间,当元素个数多了,就不适合这种了。元素个数多了就可以使用linkedlist来编码。

quicklist相当于是链表和压缩列表的结合。整体还是一个链表,链表的每个节点,是一个压缩列表,每个压缩列表,都不让它太大,同时再把多个压缩列表通过链式结构连起来。

这样的配置已经不适用了。

当前的配置项为还有一个挡位:

旧版本的策略就已经不使用了,无论什么大小都会使用quick来使用

List应用场景

用list作为数组这样的结构,来存储多个元素。

mysql中,标识学生和班级信息。

student(studented, studentName, age, score, classID)

class(classID,className) 在上述表格中我们就可以知道哪些班级有哪些人了。

redis支持这样的查询功能优点困难。

学生和班级之间的联系。 

使用Redis作为消息队列

使用生产者消费者模型。这个操作,是阻塞操作。当列表为空的时候,brpop就会阻塞等待,一直等到其他客户端,push了元素才会解除阻塞,来获取元素。谁先执行的brpop就会先拿到一个元素,像这样的设定,就构成一个轮询式的效果。

假设消费者执行顺序式 1 2 3,当新元素到达之后,首先消费者1拿到元素,(按照执行brpop的命令的先后顺序来决定谁获取到的)。消费者1拿到元素之后,也就从brpop中返回了。(相当于这个命令就执行完了)。如果消费者1还想继续消费,就需要重新执行brpop。 此时,再来一个新的元素过来,就是消费者2拿到该元素,也从brpop中返回,如果消费者2还想继续消费,也需要重新执行brpop。再来一个新元素,就是消费者3来获取这个元素了。

分频道的消息队列

多个列表/频道 这种场景非常常见的。日常使用的一些程序,抖音,有一个通道,来传输短视频数据。还可以有一个通道,来传输弹幕,还可以有频道,来传输点赞,转发,收藏数据,还可以有频道,来传输评论数据。搞成多个频道,就可以在某种数据发生问题的时候,不会对其他数据造成影响。达到了一个解耦合的目的。

微博timeline

当前一页中有多少数据不确定,可能会导致下面的循环比较大,从而会触发很多次的hgetall,也就是很多的网络请求。使用pipeline管道流水线。虽然咱们是多个redis命令,但是把这些命令合并成一个网络请求,进行通信。大大降低客户端和服务器之间的交互次数了。

lrange在两侧的查询速度很快,但是查询中间段是有点慢的。可以用这样的方法:假设某个用户发了1w个微博list长度就是1w,就可以把1w个微博拆成10份,每隔就是1k,如果是想要获取到5k个左右的微博。就可以加快中间位置的查询。

这里的list可以当作一个栈一端存取,一个队列两端存取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/452922.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL 保姆级教学】数据类型全面讲解(5)

数据类型 1. 数据类型分类1.1 数值类型1.2 文本和二进制类型1.3 日期类型 2 数值类型2.1 TINYINT 类型2.1.1 默认有符号类型2.1.2 无符号类型 2.2 INT 类型2.2.1 默认有符号类型2.2.2 无符号类型 2.3 BIT 类型2.3.1 语法2.3.2 举例 2.4 FLOAT 类型2.4.1 语法2.4.2 默认有符号类…

OpenCV高级图形用户界面(20)更改窗口的标题函数setWindowTitle()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在OpenCV中&#xff0c;cv::setWindowTitle函数用于更改窗口的标题。这使得您可以在程序运行时动态地更改窗口的标题文本。 函数原型 void cv::…

keepalived(高可用)+nginx(负载均衡)+web

环境 注意&#xff1a; (1) 做高可用负载均衡至少需要四台服务器&#xff1a;两台独立的高可用负载均衡器&#xff0c;两台web服务器做集群 (2) vip&#xff08;虚拟ip&#xff09;不能和物理ip冲突 (3) vip&#xff08;虚拟ip&#xff09;最好设置成和内网ip同一网段&#xf…

【Vulnhub靶场】Kioptrix Level 3

目标 本机IP&#xff1a;192.168.118.128 目标IP&#xff1a;192.168.118.0/24 信息收集 常规 nmap 扫存活主机&#xff0c;扫端口 根据靶机IP容易得出靶机IP为 192.168.118.133 nmap -sP 192.168.118.0/24nmap -p- 192.168.118.133 Getshell 开放22端口和80 端口 访问web…

Git极速入门

git初始化 git -v git config --global user.name "" git config --global user.email "" git config --global credential.helper store git config --global --list省略(Local) 本地配置&#xff0c;只对本地仓库有效–global 全局配置&#xff0c;所有…

第十七周:机器学习笔记

第十七周周报 摘要Abstratc一、机器学习——生成式对抗网络&#xff08;Generative Adversarial Networks | GAN&#xff09;——&#xff08;中&#xff09;1. GAN 的理论介绍2. 用JS散度训练存在的问题3. WGAN 算法4. 拓展——流体 总结 摘要 本周周报主要对GAN进行了详细的…

在ESP-IDF环境中如何进行多文件中的数据流转-FreeRTOS实时操作系统_流缓存区“xMessageBuffer”

一、建立三个源文件和对应的头文件 建立文件名&#xff0c;如图所示 图 1-1 二、包含相应的头文件 main.h 图 2-1 mess_send.h mess_rece.h和这个中类似,不明白的大家看我最后面的源码分享 图2-2 三、声明消息缓存区的句柄 大家注意&#xff0c;在main.c中定义的是全局变…

免费字体二次贩卖;刮刮乐模拟器;小报童 | 生活周刊 #4

Raycast 的两款在线工具 Raycast 公司出品&#xff0c;必属精品&#xff0c;之前的代码转图片工具&#xff0c;交互和颜值都做得很漂亮 现在又新出了一个 图标制作器&#xff0c;一键制作美观好看的图标 猫啃网 没想到像【汇文明朝体】这样免费的字体都被人拿来当成【打字机字…

基于知识图谱的电子元器件问答系统

你还在为寻找电子元器件的相关信息头疼吗&#xff1f;作为一名程序员或电子工程师&#xff0c;在项目中经常需要快速查询电子元件的属性或关联关系。今天给大家介绍一个可以大大提升工作效率的神器——基于知识图谱的电子元器件问答系统。这不仅是你学习和工作的好帮手&#xf…

vue2使用pdfjs-dist实现pdf预览(iframe形式,不修改pdfjs原来的ui和控件,dom层可以用display去掉一部分组件)

前情提要 在一开始要使用pdf预览的时候&#xff0c;第一次选的是vue-pdf&#xff0c;但是vue-pdf支持的功能太少&#xff0c;缺少了项目中需要的一项-复制粘贴功能 之后我一顿搜搜搜&#xff0c;最终貌似只有pdfjs能用 但是网上支持text-layer的貌似都是用的2.09那个版本。 使…

androidStudio编译导致的同名.so文件冲突问题解决

files found with path lib/arm64-v8a/libserial_port.so from inputs: ...\build\intermediates\library_jni\debug\jni\arm64-v8a\libserial_port.so C:\Users\...\.gradle\caches\transforms-3\...\jni\arm64-v8a\XXX.so 解决方式如下&#xff1a; 1.将gradle缓存文件删…

c++迷宫游戏

1、问题描述 程序开始运行时显示一个迷宫地图&#xff0c;迷宫中央有一只老鼠&#xff0c;迷宫的右下方有一个粮仓。游戏的任务是使用键盘上的方向健操纵老鼠在规定的时间内走到粮仓处。 基本要求: 老鼠形象可以辨认,可用键盘操纵老鼠上下左右移动&#xff1b;迷宫的墙足够结…

Android 第5种启动模式:singleInstancePerTask

Android 第5种启动模式&#xff1a;singleInstancePerTask 随着 Android 版本的更新&#xff0c;应用启动模式逐渐丰富。在 Android 12 中&#xff0c;新增了一种启动模式——singleInstancePerTask。它是继 standard、singleTop、singleTask 和 singleInstance 之后的第五种启…

大数据新视界 --大数据大厂之 Apache Beam:统一批流处理的大数据新贵

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

OpenCV高级图形用户界面(18)手动设置轨迹条(Trackbar)的位置函数setTrackbarPos()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数设置指定窗口中指定轨迹条的位置。 注意 [仅 Qt 后端] 如果轨迹条附加到控制面板&#xff0c;则 winname 可以为空。 函数原型 void cv…

插件发布新特性,让运动适配更简单。

为了让广大开发者更好的适配各AI运动场景&#xff0c;我们的AI运动识别插件已经迭代了23个版本&#xff0c;最近又迎来了我们的1.5.5小版本更新&#xff0c;本次更新了2个新特性&#xff0c;新特性有助于大家更好的适配新运动&#xff0c;更轻松的开发健身、体育、体测、AR互动…

Veritas NetBackup 10.5 发布,新增功能概览

Veritas NetBackup 10.5 发布&#xff0c;新增功能概览 Veritas NetBackup 10.5 (Unix, Linux, Windows) - 领先的企业备份解决方案 The #1 enterprise backup and recovery solution. 请访问原文链接&#xff1a;https://sysin.org/blog/veritas-netbackup-10/ 查看最新版。…

PPT自动化:快速更换PPT图片(如何保留原图片样式等参数更换图片)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 PPT更换图片 📒1. 安装 `python-pptx` 模块2. 加载PPT文件3. 查找并替换图片3.1 查找图片形状3.2 获取原图片的样式和位置3.3 替换图片4. 保存修改后的PPT文件5. 设置图片的相关参数5.1 设置透明度5.2 设置边框🚀 保留所有参…

基于springboot的网上服装商城推荐系统的设计与实现

基于springboot的网上服装商城推荐系统的设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;idea 源码获取&#xf…

upload-labs靶场Pass-01

upload-labs靶场Pass-01 分析 查看提示&#xff0c;提示如下 查看源码 function checkFile() {var file document.getElementsByName(upload_file)[0].value;if (file null || file "") {alert("请选择要上传的文件!");return false;}//定义允许上传…