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.mzph.cn/pingmian/56285.shtml

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

相关文章

16年408计算机网络

第一题&#xff1a; 解析&#xff1a; 首先我们要清楚R1,R2,R3是路由器&#xff08;网络层&#xff09;&#xff0c;Switch是以太网交换机&#xff08;数据链路层&#xff09;&#xff0c;Hub是集线器&#xff08;物理层&#xff09;。 由此可见路由器实现的最高功能层是3层&am…

如何利用phpstudy创建mysql数据库

phpStudy诞生于2007年&#xff0c;是一款老牌知名的PHP开发集成环境工具&#xff0c;产品历经多次迭代升级&#xff0c;目前有phpStudy经典版、phpStudy V8&#xff08;2019版&#xff09;等等&#xff0c;利用phpstudy可以快速搭建一个mysql环境&#xff0c;接下来我们就开始吧…

【计算机网络 - 基础问题】每日 3 题(三十六)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

Java项目:160 基于springboot物流管理系统(PPT+论文+说明文档)

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 物流管理系统有管理员和用户两个角色。 ​ 管理员功能有个人中心&#xff0c;用户管理&#xff0c;车辆信息管理&#xff0c;公告信息管理&#xff…

实现MySQL异地多活场景

作为现代化的互联网企业 &#xff0c;最怕的是什么 &#xff1f;是意外&#xff01;由各种意外导致的数据库问题&#xff0c;磁盘问题、网络问题、人员误操作问题等等&#xff0c;这些问题都可能导致数据不可用或者丢失&#xff0c;造成重大损失。 因此&#xff0c;很少会有企…

运维:winserver服务器添加nginx开机自启动

前言 发现之前做的一版windows开机自启动任务对nginx的启用无效&#xff0c;因此这里给出针对性的配置&#xff0c;以实现winserver服务器添加nginx开机自启动目的。 先前的配置方案&#xff1a;windows部署开机自启动服务_windows 服务中添加自行启动任务-CSDN博客 方案 1、进…

记录一个Ajax发送JSON数据的坑,后端RequestBody接收参数小细节?JSON对象和JSON字符串的区别?

上半部分主要介绍我实际出现的问题&#xff0c;最终下面会有总结。 起因&#xff1a;我想发送post请求的data&#xff0c;但是在浏览器中竟然被搞成了地址栏编码 如图前端发送的ajax请求数据 如图发送的请求体&#xff1a; 很明显是keyvalue这种形式&#xff0c;根本就不是…

基于Java+SpringBoot+Vue的在线文档管理系统的设计与实现

基于JavaSpringBootVue的在线文档管理系统的设计与实现 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&…

【算法题解】二分查找的经典问题解析

文章目录 什么是二分&#xff1f;关于二分的一些题目1.分巧克力解题思路编写代码 2.数组中数值和下标相等的元素3.0到n-1中缺失的数字4.数列分段 II解题思路编写代码 总结 什么是二分&#xff1f; 二分是一种思想&#xff0c;用于有序数组中快速查找目标元素。 用动图展示一下…

信息系统的生命周期

信息系统是面向现实世界人类生产、生活中的具体应用&#xff0c;是为了提高人类活动的质量、效率而存在的。信息系统的目的、性能、内部结构和秩序、外部接口、部件组成等由人来规划&#xff0c;它的产生、建设、运行和完善构成一个循环的过程&#xff0c;这个过程遵循一定的规…

【vue】指令补充+样式绑定+计算属性+侦听器

代码获取 知识总结 ⼀、指令补充 1.指令修饰符 1.1 什么是指令修饰符&#xff1f; 所谓指令修饰符就是让指令的 功能更强⼤&#xff0c;书写更便捷 1.2 分类 1.2.1 按键修饰符 keydown.enter&#xff1a;当enter键按下时触发 keyup.enter&#xff1a;当enter键抬起时触…

Jmeter脚本录制:抓取IOS手机请求包

现在移动端的项目越来越多&#xff0c;今天给大家介绍一下&#xff0c;在IOS下Jmeter如何抓包。 1、电脑连上wifi 2、Jmeter中配置“HTTP代理服务器” 1)启动Jmeter&#xff1b; 2)“测试计划”中添加“线程组”&#xff1b; 3)“测试计划”中添加“HTTP代理服务器”&…

强化学习和QLearning及GAN到底是什么关系啊

强化学习&#xff08;Reinforcement Learning&#xff09;、Q-Learning 和生成对抗网络&#xff08;GANs&#xff09;是机器学习中的三个不同概念&#xff0c;它们虽然有一些交叉&#xff0c;但本质上是针对不同问题的技术方法。下面我来详细解释它们之间的关系和区别&#xff…

Springboot 整合 Java DL4J 实现农产品质量检测系统

&#x1f9d1; 博主简介&#xff1a;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编程&#xff0c;…

图片美化SDK解决方案,赋能H5与小程序极致体验

无论是社交媒体分享、电商产品展示&#xff0c;还是个人日常生活的记录&#xff0c;一张经过精心美化的图片总能瞬间吸引眼球&#xff0c;传递出更加丰富和动人的信息。如何在不增加应用体积、不牺牲用户体验的前提下&#xff0c;为H5页面和小程序提供媲美原生APP的图片美化功能…

微信小程序-自定义组件

文章目录 微信小程序-自定义组件概述创建和使用数据、方法和属性slot 插槽默认插槽具名插槽 组件样式注意项样式隔离 数据监听组件间通信父传子子传父获取子组件实例 生命周期组件的生命周期组件所在页面的生命周期App、Page与Component生命周期对比冷启动保留当前页面和关闭当…

linux源码安装slurm以及mung和openssl

一、源码安装munge 1、编译安装munge &#xff08;1&#xff09;下载munge地址&#xff1a;https://github.com/dun/munge/releases &#xff08;2&#xff09;解压编译安装&#xff1a; 1 2 3 4 5 6 7 8 创建/data目录 复制文件munge-0.5.15.tar.xz 到/data目录下 tar -Jx…

界面耻辱纪念堂--可视元素03

更多的迹象表明&#xff0c;关于在程序里使用新的动态界面元素&#xff0c;微软的态度是不确定的&#xff0c;其中一个是仅仅需要对比一下Office97 里的“Coolbars”和“标准工具条”。Coolbar 按钮直到用户指针通过的时候才成为按钮&#xff08;否则是平的&#xff09;。 工具…

新兴的安全职业挑战

我们经常与安全专业人士交谈&#xff0c;他们希望在努力提升职业发展的同时提高自己的价值并克服组织内部的挑战。在这些谈话中&#xff0c;花费大量时间讨论公司未来将面临的安全问题并不罕见。 安全领导者希望为问题制定计划并获得领导层对其计划的支持。这通常意味着实施修…

MYSQL-windows安装配置两个或多个版本MYSQL

安装第一个mysql很简单&#xff0c;这里不再赘述。主要说说第二个怎么安装&#xff0c;服务怎么配置。 1. 从官网下载第二个MySQL并安装 一般都是免安装版了&#xff0c;下载解压到某个文件目录下(路径中尽量不要带空格或中文)&#xff0c;再新建一个my.ini文件&#xff08;或…