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可以当作一个栈一端存取,一个队列两端存取。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

12月17-19日 | 2024南京软博会,持续升级中!

2024中国&#xff08;南京&#xff09;软件产业博览会&#xff08;简称“南京软博会”&#xff09;自2005年以来&#xff0c;已连续举办19年&#xff0c;集新品发布、产品交易、人才交流、项目对接等功能为一体&#xff0c;成为全国软件产业品牌展会和对外窗口。 今年是南京软…

ubuntu 安装keepalived+haproxy

一、安装keepalived sudo apt update sudo apt install keepalived sudo systemctl start keepalived sudo systemctl enable keepalived sudo systemctl status keepalived#配置Keepalived sudo cp /etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf …

informer学习笔记

一、informer讲解 infomer 要解决的三大问题&#xff1a; Attention计算的更快Decoder要一次性输出所有预测堆叠encoder也要更快 1. Attention 在长序列中&#xff0c;并非每一个位置的Attention都重要&#xff0c;对于每一个Q来说&#xff0c;只有一小部分的K与其有较强的…

java互联网医院智能导诊系统源码,Uniapp前端开发框架,支持一次编写,多端运行

智慧导诊系统源码&#xff0c;java源码&#xff0c;大屏机自动导诊&#xff0c;互联网医院智能导诊系统源码 老是全身无力&#xff0c;挂什么科&#xff1f; 经常头痛&#xff0c;挂什么科&#xff1f; 总是失眠&#xff0c;又得挂哪个科&#xff1f; 世界上最遥远的距离再加…

企业内训|LLM大模型技术在金融领域的应用及实践-某商业银行分行IT团队

本企业培训是TsingtaoAI技术团队专们为某商业银行分行IT团队开发的LLM大模型技术课程。课程深入分析大模型在金融行业中的发展趋势、底层技术及应用场景&#xff0c;重点提升学员在大模型应用中的实际操作能力与业务场景适应力。通过对全球商用 LLM 产品及国内外技术生态的深度…

每天五分钟深度学习框架pytorch:基于pytorch搭建多变量回归模型

本文重点 前面我们学习了基于pytorch搭建多项式回归模型,我们也知道了它和多变量回归模型的区别,本文我们使用pytorch搭建多变量回归模型 模型搭建 class Multivariable_Regression(nn.Module):def __init__(self):super(Multivariable_Regression,self).__init__()self.po…

基于PHP+MySQL+Vue的网上订餐系统

摘要 本文介绍了一个基于PHPMySQLVue技术的网上订餐系统。该系统旨在为用户提供便捷的在线订餐服务&#xff0c;同时提高餐厅的运营效率。系统后端采用PHP语言开发&#xff0c;利用MySQL数据库进行数据存储与管理&#xff0c;实现了用户注册登录、菜品浏览、购物车管理、订单提…

hi3798mv100 linux 移植

# Linux开发环境搭建 ## uboot编译 1. 必须先安装gcc&#xff0c;要不然make 等命令无法使用 2. 配置arm 交叉编译链 # gcc sudo apt-get install gcc-9 gcc -v# 安装 Linaro gcc-arm-linux-gnueabihf&#xff0c;注意不是arm-linux-gnueabihf-gcc sudo apt-get install ar…

老机MicroServer Gen8再玩 OCP万兆光口+IT直通

手上有一台放了很久的GEN8微型服务器&#xff0c;放了很多年&#xff0c;具体什么时候买的我居然已经记不清了 只记得开始装修的时候搬家出去就没用了&#xff0c;结果搬出去有了第1个孩子&#xff0c;孩子小的时候也没时间折腾&#xff0c;等孩子大一点的时候&#xff0c;又有…

流量PID控制(开度前馈量计算+辅助PID)

和流体流速(瞬时流量)相关的计算请参考下面文章链接: 1、PLC通过伯努利方程近似计算水箱流量 PLC通过伯努利方程近似计算水箱流量(FC)-CSDN博客文章浏览阅读1.6k次。本文介绍了如何使用PLC通过伯努利方程近似计算水箱中的液体流量,主要涉及流量计算、模型验证、梯形图编程及…

【NLP】GloVe模型

一、Glove简介 GloVe (Global Vectors for Word Representation) 是一种基于词共现矩阵的词向量生成方法&#xff0c;由斯坦福大学的 Jeffrey Pennington、Richard Socher 和 Christopher D. Manning 提出。与 Word2Vec 不同&#xff0c;GloVe 通过全局统计信息&#xff08;词…

如何用AI大模型提升挖洞速度

工具背景 越权漏洞在黑盒测试、SRC挖掘中几乎是必测的一项&#xff0c;但手工逐个测试越权漏洞往往会耗费大量时间&#xff0c;而自动化工具又存在大量误报, 基于此产生了AutorizePro&#xff0c; 那它是怎么提升效率一起来看看 AutorizePro 是一款专注于越权检测的 Burp 插件…

vue综合指南(二)

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vuet篇专栏内容:vue综合指南(二) 目录 21、介绍虚拟DOM 22、vue生命周期的理解 23、vue父组件向子组件传递数据…

基于SpringBoot+Vue+uniapp微信小程序的社区门诊管理系统的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

11 图书借阅功能实现(Vue3+element plus +Spring Boot)

目录 1 功能描述2 接口地址3 后端代码4 api/book.js中编写借阅图书的接口代码5 BookResourcesVue.vue组件中完成点击事件borrowBook6 功能演示 1 功能描述 普通用户借阅图书&#xff0c;点击借阅按钮&#xff0c;修改图书状态&#xff0c;最多能够借阅3本图书。 2 接口地址 …

Vulnhub:Me-and-My-Girlfriend-1

一.环境启动/信息收集 &#xff08;1&#xff09;根据物理地址用nmap的主机发现功能得出IP地址 nmap -P 192.168.138.0/24 //同网段下主机发现得到IP为192.168.138.180&#xff08;2&#xff09;做nmap的目录扫描和端口扫描来发现其他站带以及信息 nmap -p- 192.168.138.180 …

Gin框架操作指南08:日志与安全

官方文档地址&#xff08;中文&#xff09;&#xff1a;https://gin-gonic.com/zh-cn/docs/ 注&#xff1a;本教程采用工作区机制&#xff0c;所以一个项目下载了Gin框架&#xff0c;其余项目就无需重复下载&#xff0c;想了解的读者可阅读第一节&#xff1a;Gin操作指南&#…

Docker-Harbor概述及构建

文章目录 一、Docker Harbor概述1.Harbor的特性2.Harbor的构成 二、搭建本地私有仓库三、部署 Docker-Harbor 服务四、在其他客户端上传镜像五、维护管理Harbor 一、Docker Harbor概述 Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c;其目标是帮助用户迅…

Java项目-基于springboot框架的社区疫情防控平台系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

新手必须掌握的Linux命令

1.1 常用系统工作命令 echo [linuxprobelocalhost /]$ echo $SHELL /bin/bash 使用$变量的方式提取SHELL的值&#xff0c;并输出到到屏幕上 date [linuxprobelocalhost /]$ date -s "20170901 8:30:00" 将系统时间设置为 reboot ----系统重启命令poweroff --…