3.redis数据结构之List

List-列表类型:L&R

列表类型:有序、可重复

Arraylist和linkedlist的区别

Arraylist是使用数组来存储数据,特点:查询快、增删慢

Linkedlist是使用双向链表存储数据,特点:增删快、查询慢,但是查询链表两端的数据也很快。

Redis的list是采用来链表来存储的,所以对于redis的list数据类型的操作,是操作list的两端数据来操作的。

命令

向列表左边增加元素:lpush key:val1 val2

127.0.0.1:6379>lpush list:1 1 2 3 (integer) 3

向列表右边增加元素:rpush key:val1 val2

127.0.0.1:6379>rpush list:1 4 5 6 (integer) 3

查看列表:LRANGE key start stop

LRANGE命令是列表类型最常用的命令之一,获取列表中的某一片段,将返回start、stop之间的所有元素(包含两端的元素),索引从0开始。索引可以是负数,如:“-1”代表最后边的一个元素。

语法:LRANGE key start stop 获取下标0-2的元素 前闭后闭 127.0.0.1:6379> lrange list1 0 2 1) "2" 2) "1" 3) "4" ​ 这里需要注意的是,list的索引从0开始大家知道,但是取全部list的值时,结束索引需要设置为-1,也可以设置成list长度减1 127.0.0.1:6379> lrange l:list 0 -1 1) "6" 2) "5" 3) "2" 4) "2"

从列表两端弹出元素:LPOP key&RPOP key

LPOP命令从列表左边弹出一个元素,会分两步完成:

第一步是将列表左边的元素从列表中移除

第二步是返回被移除的元素值。

语法: LPOP key RPOP key 127.0.0.1:6379> lpop list:1 "3“ 127.0.0.1:6379> rpop list:1 "6“

获取列表中元素的个数LLEN key

语法:LLEN key 127.0.0.1:6379> llen list:1 (integer) 2

删除列表中指定的值 LREM key count value

LREM命令会删除列表中前count个值为value的元素,返回实际删除的元素个数。根据count值的不同,该命令的执行方式会有所不同: 当count>0时, LREM会从列表左边开始删除。 当count<0时, LREM会从列表后边开始删除。 当count=0时, LREM删除所有值为value的元素。 删除2个值为1的元素 语法:LREM key count value 127.0.0.1:6379> lrem list1 2 1 (integer) 2

获得/设置指定索引的元素值LINDEX key index

获得指定索引的元素值 语法:LINDEX key index 127.0.0.1:6379> lindex list 2 "1" ​ 设置指定索引的元素值 语法:LSET key index value 127.0.0.1:6379> lset list 2 2 OK

只保留列表指定范围元素:LTRIM key start stop

只保留start - stop 之间的元素 语法:LTRIM key start stop 127.0.0.1:6379> lrange l:list 0 -1 1) "6" 2) "5" 3) "0" 4) "2" 127.0.0.1:6379> ltrim l:list 0 2 OK 127.0.0.1:6379> lrange l:list 0 -1 1) "6" 2) "5" 3) "0"

向列表中插入元素LINSERT key BEFORE|AFTER pivot value

该命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。 ​ 语法:LINSERT key BEFORE|AFTER pivot value 127.0.0.1:6379> lrange list 0 -1 1) "3" 2) "2" 3) "1" ​ 将值为4的元素插入到3后面 127.0.0.1:6379> linsert list after 3 4 (integer) 4 127.0.0.1:6379> lrange list 0 -1 1) "3" 2) "4" 3) "2" 4) "1"

将A列表最后一个元素移到B列表RPOPLPUSH source destination

用于移除列表的最后一个元素,并将该元素添加到另一个列表并返回。

语法:RPOPLPUSH source destination ​ 127.0.0.1:6379> lrange list 0 -1 1) "3" 2) "4" 3) "2" 4) "1" 127.0.0.1:6379> rpoplpush list newlist "1" 127.0.0.1:6379> lrange newlist 0 -1 1) "1" 127.0.0.1:6379> lrange list 0 -1 1) "3" 2) "4" 3) "2"

移出并获取列表的最后一个元素(阻塞):Brpop

移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

redis 127.0.0.1:6379> BRPOP LIST1 LIST2 .. LISTN TIMEOUT

假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。

redis> DEL list1 list2 (integer) 0 redis> RPUSH list1 a b c (integer) 3 redis> BRPOP list1 list2 0 1) "list1" 2) "c"

将A列表最后一个元素移到B列表(阻塞)Brpoplpush

命令从列表中取出最后一个元素,并插入到另外一个列表的头部; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。

``` redis 127.0.0.1:6379> BRPOPLPUSH LIST1 ANOTHER_LIST TIMEOUT

非空列表

​ redis> BRPOPLPUSH msg reciver 500 "hello moto"                       # 弹出元素的值 (3.38s)                             # 等待时长 ​ redis> LLEN reciver (integer) 1 ​ redis> LRANGE reciver 0 0 1) "hello moto" ​ ​

空列表

​ redis> BRPOPLPUSH msg reciver 1 (nil) (1.34s) ```

应用场景:大容量&更新频率不高&的静态列表

商品评论列表

思路

在Redis中创建商品评论列表

用户发布商品评论,将评论信息转成json存储到list中。

用户在页面查询评论列表,从redis中取出json数据展示到页面。

定义商品评论列表key

商品编号为1001的商品评论key【items: comment:1001】

每日排行榜:某个时间段数据固定榜单

 list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中,如京东每日的手机销量排行、学校每次月考学生的成绩排名、斗鱼年终盛典主播排名等,下图是酷狗音乐“K歌擂台赛”的昨日打擂金曲排行榜,每日计算一次,存储在list类型中,接口访问时,通过page和size分页获取打擂金曲。

list类型的lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表,如朋友圈的点赞列表、评论列表。 ​   但是,并不是所有的最新列表都能用list类型实现,因为对于频繁更新的列表,list类型的分页可能导致列表元素重复或漏掉,举个例子,当前列表里由表头到表尾依次有(E,D,C,B,A)五个元素,每页获取3个元素,用户第一次获取到(E,D,C)三个元素,然后表头新增了一个元素F,列表变成了(F,E,D,C,B,A),此时用户取第二页拿到(C,B,A),元素C重复了。可以尾插头拿 即 左边插入从右边拿。   只有不需要分页(比如每次都只取列表的前5个元素)或者更新频率低(比如每天凌晨更新一次)的列表才适合用list类型实现。   对于需要分页并且会频繁更新的列表,需用使用有序集合sorted set类型实现。   另外,需要通过时间范围查找的最新列表,list类型也实现不了,也需要通过有序集合sorted set类型实现,如以成交时间范围作为条件来查询的订单列表。之后在介绍有序集合sorted set类型的应用场景时会详细介绍sorted set类型如何实现最新列表。 ​   那么问题来了,对于排行榜和最新列表两种应用场景,list类型能做到的sorted set类型都能做到,list类型做不到的sorted set类型也能做到,那为什么还要使用list类型去实现排行榜或最新列表呢,直接用sorted set类型不是更好吗?   原因是sorted set类型占用的内存容量是list类型的数倍之多(之后会在容量章节详细介绍),对于列表数量不多的情况,可以用sorted set类型来实现,比如上文中举例的打擂金曲排行榜,每天全国只有一份,两种数据类型的内存容量差距可以忽略不计,但是如果要实现某首歌曲的翻唱作品地区排行榜,数百万的歌曲,300多个地区,会产生数量庞大的榜单,或者数量更加庞大的朋友圈点赞列表,就需要慎重地考虑容量的问题了。

底层数据结构压缩列表和双向链表


在版本3.2之前,Redis 列表list使用两种数据结构作为底层实现:

  • 压缩列表ziplist
  • 双向链表linkedlist
  • 因为双向链表占用的内存比压缩列表要多, 所以当创建新的列表键时, 列表会优先考虑使用压缩列表, 并且在有需要的时候, 才从压缩列表实现转换到双向链表实现。

ziplist

ziplist 是一个特殊的双向链表 特殊之处在于:没有维护双向指针:prev next;而是存储上一个 entry的长度和 当前entry的长度,通过长度推算下一个元素在什么地方。 牺牲读取的性能,获得高效的存储空间,因为(简短字符串的情况)存储指针比存储entry长度 更费内存。这是典型的“时间换空间”。

ziplist使用局限性 字段、值比较小,才会用ziplist。

压缩列表ziplist存储结构 ziplist使用连续的内存块,每一个节点(entry)都是连续存储的;

1.ziplist可以通过data header计算出当前entry的结束位置,也就能得到下一个entry的起始位置,正向遍历

2.ziplist可以通过length of previous entry计算出上一个entry的起始位置,反向遍历

压缩列表转化成双向链表条件

创建新列表时 redis 默认使用 redisencodingziplist 编码, 当以下任意一个条件被满足时, 列表会被转换成 redisencodinglinkedlist 编码:

  • 试图往列表新添加一个字符串值,且这个字符串的长度超过 server.listmaxziplist_value (默认值为 64字节)。
  • ziplist 包含的节点超过 server.listmaxziplist_entries (默认值为 512 )。

注意:这两个条件是可以修改的,在 redis.conf 中:

list-max-ziplist-value 64 list-max-ziplist-entries 512

linkedlist

当链表entry数据超过512、或单个value 长度超过64字节,底层就会转化成linkedlist编码; linkedlist是标准的双向链表,Node节点包含prev和next指针,可以进行双向遍历; 还保存了 head 和 tail 两个指针,因此,对链表的表头和表尾进行插入的复杂度都为 (1) —— 这是高效实现 LPUSH 、 RPOP、 RPOPLPUSH 等命令的关键。

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

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

相关文章

设计模式——接口隔离原则

文章目录 基本介绍应用实例应传统方法的问题和使用接口隔离原则改进 基本介绍 客户端不应该依赖它不需要的接口&#xff0c;即一个类对另一个类的依赖应该建立在最小的接口上先看一张图: 类 A 通过接口 Interface1 依赖类 B&#xff0c;类 C 通过接口 Interface1 依赖类 D&…

数据结构,查找算法(二分,分块,哈希)

一、查找算法 1、二分查找:(前提条件: 必须有序的序列) #include <stdio.h> //二分查找 value代表的是被查找的值 int findByHalf(int *p, int n, int value) {int low = 0;//low低int high = n-1;//high高int middle;//用来保存中间位置的下标while(low <= high…

通用vue项目应对定制化时该如何组件化

分析页面-页面组件化 之前写了一个项目&#xff0c;大屏页面是通用页面但是遇到个别用户想要定制化&#xff0c;但是主页如果去做判断显得太过臃肿&#xff0c;后续也无法判断&#xff0c;由于公司不想维护多套代码&#xff0c;于是就考虑抽离成组件&#xff01;直接看代码&…

electron的使用和操作

文章目录 先创建一个基本的electron应用electron生命周期事件单个窗体事件创建窗体时所携带的一些属性 先创建一个基本的electron应用 先安装 npm install --save-dev electron然后在package.json里面创建如下内容 {"name": "my-electron-app","ve…

shell脚本语句(画矩形、三角形、乘法表和小游戏)(#^.^#)

目录 一、语句 一、条件语句 一、以用户为例演示 一、显示当前登录系统的用户信息 二、显示有多少个用户 二、单分支if 一、输入脚本 二、验证结果 三、双分支if 一、输入脚本 二、验证结果 四、多分支if 一、输入脚本 二、验证 二、循环语句 一、shell版本的循环…

vue的图片懒加载

安装&#xff1a; vueuse 插件 npm i vueuse/core 搜索&#xff1a; useIntersectionObserver 方法 import { ref } from vue import { useIntersectionObserver } from vueuse/coreexport default {setup() {const target ref(null)const targetIsVisible ref(false…

c语言关键字_ _align()和_ _packed的使用以及字节对齐原理

c语言中__align()关键字的作用与内存对齐的原理 1、什么是字节对齐 字节对齐(Byte Alignment)是计算机内存中的一种存储优化技术,用于确保数据在内存中的存储位置满足特定的硬件要求,以提高内存访问的效率。在现代计算机体系结构中,许多处理器要求数据以特定的方式对齐,…

k8s集群中service的域名解析、pod的域名解析

前言 在k8s集群中&#xff0c;service和pod都可以通过域名的形式进行相互通信&#xff0c;换句话说&#xff0c;在k8s集群内&#xff0c;通过service和pod的域名&#xff0c;可以直接访问内部应用&#xff0c;不必在通过service ip地址进行通信&#xff0c;一般的&#xff0c;…

空调企业只干空调,卡萨帝却干了业主想不到的事

作者 | 曾响铃 文 | 响铃说 今年入夏以来&#xff0c;随着气温的不断攀升&#xff0c;空调已经成为生活、工作中的“绝对刚需”。由此而来的则是空调产品的销量大增。 但也有不少消费者表示&#xff0c;随着产品功能的越发相似&#xff0c;价格趋同&#xff0c;使空调变得越…

类的加载过程二:Linking

1、验证&#xff08;Verify&#xff09; 目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求&#xff0c;保证被加载类的正确性&#xff0c;不会危害虚拟机自身安全。主要包括四种验证&#xff0c;文件格式验证&#xff0c;元数据验证&#xff0c;字节码验证&#xff…

Postman 如何进行参数化

前言 Postman作为一款接口测试工具&#xff0c;受到了非常多的开发工程师的拥护。 那么做为测试&#xff0c;了解Postman这款工具就成了必要的了。 这篇文章就是为了解决Postman怎么进行参数化的。 全局变量 全局变量是将这个变量设置成整个程序的都可以用&#xff0c;不用去…

装箱和拆箱

1. 概念 装箱 将值类型转换成等价的引用类型 装箱的步骤 拆箱 将一个已装箱的引用类型转换为值类型&#xff0c;拆箱操作需要声明拆箱后转换的类型 拆箱的步骤 1&#xff09;获取已装箱的对象的地址 2&#xff09;将值从堆上的对象中复制到堆栈上的值变量中 2. 总结 装箱和拆箱…

数组指针、函数指针、指针数组、函数 指针数组、指针函数详细总结

1.数组指针概念和应用 首先数组指针应该是一个数组&#xff0c;它的定义如下&#xff1a; 数组指针&#xff0c;指的是数组名的指针&#xff0c;即数组首元素地址的指针。即是指向数组的指针。例&#xff1a;int (*p)[10]; p即为指向数组的指针&#xff0c;又称数组指针。 数…

Microsoft Visual Studio + Qt插件编程出现错误error MSB4184问题

文章目录 报错解决 报错 C:\Users\Administrator\AppData\Local\QtMsBuild\qt_globals.targets(786,7): error MSB4184: 无法计算表达式“[System.IO.File]::ReadAllText(C:\Users\Administrator\AppData\Local\QtMsBuild\qt.natvis.xml)”。 未能找到文件“C:\Users\Administ…

C语言:指针(超深度讲解)

目录 指针&#xff1a; 学习目标&#xff1a; 指针可以理解为&#xff1a; 字符指针&#xff1a; 定义&#xff1a;字符指针 char*。 字符指针的使用&#xff1a; 练习&#xff1a; 指针数组&#xff1a; 概念&#xff1a;指针数组是一个存放指针的数组。 实现模拟二维…

NetApp EF 系列全闪存阵列 EF600 和 EF300 ——经济实惠、性能极高的全闪存存储系统、 适用于各种混合型企业工作负载

NetApp EF 系列全闪存阵列 EF600 和 EF300 ——经济实惠、性能极高的全闪存存储系统、 适用于各种混合型企业工作负载 功能强大且经济实惠的性能 NetApp EF600 全闪存阵列专为需要最高性能的工作负载而设计。NetApp EF300 阵列专为大数据分析和数据库等混合工作负载环境而设计…

NPDP认证适合什么人考?这个职业必考!

NPDP认证全称为New Product Development Professional&#xff0c;是指由Product Development and Management Association&#xff08;PDMA&#xff09;颁发的产品经理国际资格认证认证。 NPDP认证旨在评估和认证具有新产品开发知识、技能和经验的个人。与PMP证书不同&#x…

MySQL 临时表与内存表的区别

文章目录 1.临时表2.内存表3.区别4.小结 在 MySQL 中&#xff0c;Temporary Table&#xff08;临时表&#xff09;和 Memory Table&#xff08;内存表&#xff09;是两种不同的表类型&#xff0c;它们有一些重要的区别和用途。 1.临时表 临时表&#xff08;Temporary Table&a…

AMBA总线协议(8)——AHB(六):分割传输

一、前言 在之前的文章中&#xff0c;我们重点介绍了AHB传输的仲裁&#xff0c;首先介绍了仲裁相关的信号&#xff0c;然后分别介绍了请求总线访问&#xff0c;授权总线访问&#xff0c;猝发提前终止&#xff0c;锁定传输和默认主机总线&#xff0c;在本文中我们将继续介绍AHB的…

网络编程套接字(1)

文章目录 网络编程套接字(1)1. 预备知识1.1 源IP与目的IP1.2 认识端口号1.3 理解 "端口号" 和 "进程ID"1.4 源端口号和目的端口号1.5 认识TCP协议和UDP协议(1) TCP(2) UDP 1.6 网络字节序 2. socket编程接口2.1 socket 常见API2.2 sockaddr结构 网络编程套…