Redis List类型

列表类型是用来存储多个有序的字符串,如图所示,a、b、c、d、e 五个元素从左到右组成了一个有序的列表,列表中的每个字符串称为元素 (element),一个列表最多可以存储2的32次方 -1个元素。在 Redis 中,可以对列表两端插入(push)和弹出 (pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。

列表两端插入和弹出操作

在这里插入图片描述

列表的获取、删除等操作

在这里插入图片描述

列表类型的特点

  1. 列表中的元素是有序的,这意味着可以通过索引下标获取某个元素或者某个范围的元素列表,例如要获取下图的第5个元素,可以执行lindex user:1:messages 4 或者倒数第1个元素,lindexuser:1:messages-1就可以得到元素e。
  2. 区分获取和删除的区别,例如图中的rem 1b 是从列表中把从左数遇到的前1个b元素删除,这个操作会导致列表的长度从5变成4;但是执行 index4 只会获取元素,但列表长度是不会变化的。
  3. 列表中的元素是允许重复的,例如图中的列表中是包含了两个a元素的。

列表中允许有重复元素

在这里插入图片描述

命令

lpush

将一个或多个值插入到 Redis 列表的头部。如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。当 key 存在但不是列表类型时,返回一个错误。

语法

LPUSH key value1 [value2 ...]
  • key 是列表的名字。
  • value1 是要插入的值。可以同时指定多个值,Redis 会从左到右的顺序将它们插入到列表的头部。

时间复杂度:只插入一个元素为 O(1),插入多个元素为 O(N),N 为插入元素个数

返回值:返回列表的长度。

示例

127.0.0.1:6379> lpush mylist "world"
(integer) 1
127.0.0.1:6379> lpush mylist "hello"
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "world"

lpushx

在 key 存在时,将一个或者多个元素从左侧放入(头插)到 list 中。不存在,直接返回

语法

LPUSHX key value1 [value2 ...]

时间复杂度:只插入一个元素为 O(1),插入多个元素为 O(N),N 为插入元素个数

返回值:插入后 list 的长度。

示例

127.0.0.1:6379> lpush mylist "World"
(integer) 1
127.0.0.1:6379> lpushx mylist "Hello"
(integer) 2
127.0.0.1:6379> lpushx myotherlist "Hello"
(integer) 0
127.0.0.1:6379> lrange mylist 0 -1
1) "Hello"
2) "World"
127.0.0.1:6379> lrange myotherlist 0 -1
(empty array)

rpush

将一个或者多个元素从右侧放入(尾插)到 list 中。

语法

RPUSH key value [value ...]

时间复杂度:只插入一个元素为 O(1),插入多个元素为 O(N),N 为插入元素个数

返回值:插入后 list的长度

示例

127.0.0.1:6379> rpush mylist "world"
(integer) 1
127.0.0.1:6379> rpush mylist "hello"
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "world"
2) "hello"

rpushx

在 key 存在时,将一个或者多个元素从右侧放入(尾插)到list 中。

语法

RPUSHX key value1 [value2 ...]

时间复杂度:只插入一个元素为 O(1),插入多个元素为 O(N),N 为插入元素个数

返回值:插入后 list 的长度。

示例

127.0.0.1:6379> rpush mylist "World"
(integer) 1
127.0.0.1:6379> rpushx mylist "Hello"
(integer) 2
127.0.0.1:6379> rpushx myotherlist "Hello"
(integer) 0
127.0.0.1:6379> lrange mylist 0 -1
1) "World"
2) "Hello"
127.0.0.1:6379> lrange myotherlist 0 -1
(empty array)

lrange

获取从 start 到 end 区间的所有元素,左闭右闭。

语法

LRANGE key start stop

时间复杂度:O(N)

返回值:指定区间的元素。

示例

127.0.0.1:6379> rpush mylist "one"
(integer) 1
127.0.0.1:6379> rpush mylist "two"
(integer) 2
127.0.0.1:6379> rpush mylist "three"
(integer) 3
127.0.0.1:6379> lrange mylist 0 0
1) "one"
127.0.0.1:6379> lrange mylist -3 2
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> lrange mylist -100 100
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> lrange mylist 5 10
(empty array)

lpop

从 list 左侧取出元素(即头删)

语法

LPOP key

时间复杂度:O(1)

返回值:取出的元素或者 nil。

示例

127.0.0.1:6379> rpush mylist "one" "two" "three" "four" "five"
(integer) 5
127.0.0.1:6379> lpop mylist
"one"
127.0.0.1:6379> lpop mylist
"two"
127.0.0.1:6379> lpop mylist
"three"
127.0.0.1:6379> lrange mylist 0 -1
1) "four"
2) "five"

rpop

从 list 右侧取出元素 (即尾删)

语法

RPOP key

时间复杂度:O(1)

返回值:取出的元素或者 nil。

示例

127.0.0.1:6379> rpush mylist "one" "two" "three" "four" "five"
(integer) 5
127.0.0.1:6379> rpop mylist
"five"
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "two"
3) "three"
4) "four"

lindex

获取从左数第 index 位置的元素。

语法

LINDEX key index

时间复杂度:O(N)

返回值:取出的元素或者 nil。

示例

127.0.0.1:6379> lpush mylist "World"
(integer) 1
127.0.0.1:6379> lpush mylist "Hello"
(integer) 2
127.0.0.1:6379> lindex mylist 0
"Hello"
127.0.0.1:6379> lindex mylist -1
"World"
127.0.0.1:6379> lindex mylist 3
(nil)

linsert

在特定位置插入元素。

语法

LINSERT key BEFORE|AFTER pivot value

这里:

  • key 是列表的键名。
  • BEFOREAFTER 是插入位置选项,用于指定新值是插在参考值的前面还是后面。
  • pivot 是列表中的现有值,新值会插入到这个值的前面或后面。
  • value 是要插入的新值。

时间复杂度:O(N)

返回值:插入后的 list 长度。

示例

127.0.0.1:6379> rpush mylist "Hello"
(integer) 1
127.0.0.1:6379> rpush mylist "World"
(integer) 2
127.0.0.1:6379> linsert mylist before "World" "There"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "Hello"
2) "There"
3) "World"

llen

获取 list 长度

语法

LLEN key

时间复杂度:O(1)

返回值:list 的长度。

示例

127.0.0.1:6379> lpush mylist "World"
(integer) 1
127.0.0.1:6379> lpush mylist "Hello"
(integer) 2
127.0.0.1:6379> llen mylist
(integer) 2

阻塞版本命令

blpop 和 brpop 是 lpop 和 rpop 的阻塞版本,和对应非阻塞版本的作用基本⼀致,除了:

  • 在列表中有元素的情况下,阻塞和非阻塞表现是一致的。但如果列表中没有元素,非阻塞版本会理解返回nil,但阻塞版本会根据timeout,阻塞一段时间,期间 Redis 可以执行其他命令,但要求执行该命令的客户端会表现为阻塞状态。
  • 命令中如果设置了多个键,那么会从左向右进行遍历键,一旦有一个键对应的列表中可以弹出元素,命令立即返回。
  • 如果多个客户端同时多一个键执行 pop,则最先执行命令的客户端会得到弹出的元素。

阻塞版本的 blpop 和 非阻塞版本 lpop 的区别

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

blpop

语法

BLPOP key [key ...] timeout

时间复杂度:O(1)

返回值:取出的元素或者 nil。

示例

127.0.0.1:6379> blpop list1 0
1) "list1"
2) "a"
127.0.0.1:6379> blpop list1 60
1) "list1"
2) "b"
127.0.0.1:6379> blpop list1 60
1) "list1"
2) "c"
#开启另一个终端
127.0.0.1:6379> lpush list1 d
(integer) 1
#原来终端
127.0.0.1:6379> blpop list1 60
1) "list1"
2) "d"
(14.63s)

brpop

语法

BRPOP key [key ...] timeout

时间复杂度:O(1)

返回值:取出的元素或者 nil。

示例

127.0.0.1:6379> del list1
(integer) 0
127.0.0.1:6379> rpush list1 a b c
(integer) 3
127.0.0.1:6379> brpop list1 60
1) "list1"
2) "c"
127.0.0.1:6379> brpop list1 60
1) "list1"
2) "b"
127.0.0.1:6379> brpop list1 60
1) "list1"
2) "a"
#另一个终端运行
127.0.0.1:6379> lpush list1 d
(integer) 1
#原来终端
127.0.0.1:6379> brpop list1 60
1) "list1"
2) "d"
(7.83s)

内部编码

list 类型的内部编码有两种:

  • ziplist (压缩列表):当列表的元素个数小于 list-max-ziplist-entries 配置(默认512个),同时列表中每个元素的长度都小于 list-max-ziplist-value 配置(默认64 字节)时,Redis 会选用 ziplist 来作为列表的内部编码实现来减少内存消耗。
  • linkedlist (链表):当列表类型无法满足 ziplist 的条件时,Redis 会使用 linkedlist 作为列表的内部实现。

1)当元素个数较少且没有大元素时,内部编码为 ziplist:

127.0.0.1:6379> rpush listkey e1 e2 e3
(integer) 3
127.0.0.1:6379> object encoding listkey
"ziplist"

2)当元素个数超过 512 时,内部编码为 linkedlist:

127.0.0.1:6379> rpush listkey e1 e2 e3 ... 省略 e512 e513
OK
127.0.0.1:6379> object encoding listkey
"linkedlist"

3)当某个元素的长度超过 64 字节时,内部编码为 linkedlist:

127.0.0.1:6379> rpush listkey "one string is bigger than 64 bytes ... 省略 ..."
OK
127.0.0.1:6379> object encoding listkey
"linkedlist"

使用场景

消息队列

Redis 可以使用 lpush + brpop 命令组合实现经典的阻塞式生产者-消费者模型队列, 生产者客户端使用 lpush 从列表左侧插⼊元素,多个消费者客户端使用 brpop 命令阻塞式地从队列中 “争抢” 队首元素。通过多个客户端来保证消费的负载均衡和高可用性。

Redis 阻塞消息队列模型

在这里插入图片描述

分频道的消息队列

Redis 同样使用 lpush + brpop 命令,但通过不同的键模拟频道的概念,不同的消费者可以通过 brpop 不同的键值,实现订阅不同频道的理念。

Redis 分频道阻塞消息队列模型

在这里插入图片描述

微博 Timeline

每个用户都有属于自己的 Timeline (微博列表),现需要分页展示文章列表。此时可以考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素。

1)每篇微博使用哈希结构存储,例如微博中 3 个属性:title、timestamp、content:

hmset mblog:1 title xx timestamp 1476536196 content xxxxx
...
hmset mblog:n title xx timestamp 1476536196 content xxxxx

2)向用户 Timeline 添加微博,user::mblogs 作为微博的键:

lpush user:1:mblogs mblog:1 mblog:3
...
lpush user:k:mblogs mblog:9

3)分页获取用户的 Timeline,例如获取用户 1 的前 10 篇微博:

keylist = lrange user:1:mblogs 0 9
for key in keylist {
 	hgetall key
}

此方案在实际中可能存在两个问题:

  • 1+n 问题。即如果每次分页获取的微博个数较多,需要执行多次 hgetall 操作,此时可以考虑使用 pipeline (流水线)模式批量提交命令,或者微博不采用哈希类型,而是使用序列化的字符串类型,使用 mget 获取。
  • 分裂获取文章时,lrange 在列表两端表现较好,获取列表中间的元素表现较差,此时可以考虑将列表做拆分。

选择列表类型时,请参考

同侧存取(lpush + lpop 或者 rpush + rpop)为栈
异侧存取(lpush + rpop 或者 rpush + lpop)为队列

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

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

相关文章

Kafka-Kafka核心参数详解

Kafka的HighLevel API使用是非常简单的,所以梳理模型时也要尽量简单化,主线清晰,细节慢慢扩展。 Kafka提供了两套客户端API,HighLevel API和LowLevel API。 HighLevel API封装了kafka的运行细节,使用起来比较简单&…

RabbitMQ消息顺序性保障

RabbitMQ 没有属性设置消息的顺序性,只能设置消息的优先级,因此消息顺序性保障只能在 consumer 上实现 场景分析: 生产者向 RabbitMQ 里发送了三条数据, 顺序依次是 data1-> data2 -> data3,压入的是一个内存…

DeepCorr:利用深度学习进行Tor的流关联攻击

文章信息 论文题目:DeepCorr: Strong Flow Correlation Attacks on Tor Using Deep Learning 期刊(会议):Proceedings of the 2018 ACM SIGSAC Conference on Computer and Communications Security 时间:2018 级别&a…

android下的app性能测试应主要针对那些方面,如何开展?

如何开展安卓手机下的App性能测试,对于优秀的测试人员而言,除了要懂得性能测试的步骤流程外,还应该懂的性能测试的一些其他知识,比如性能测试指标、各指标的意义,常用的性能测试工具、如何查看结果分析等等知识。所以本…

ES6 面试题 | 13.精选 ES6 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

(五)STM32 按键输入实验及 GPIO做普通 IO 的注意事项

目录 1. 按键硬件连接 2. 按键软件设计 3. 按键消抖 4. 使用 IO 口时的 注意事项(踩坑) 上一节我们介绍了 STM32F1 的 IO 口作为输出的使用,这一章,我们将介绍如何使用 STM32F1 的 IO 口作为输入用。在本章中,我们…

网络(十)ACL和NAT

前言 网络管理在生产环境和生活中,如何实现拒绝不希望的访问连接,同时又要允许正常的访问连接?当下公网地址消耗殆尽,且公网IP地址费用昂贵,企业访问Internet全部使用公网IP地址不够现实,如何让私网地址也…

Java 基础学习(十一)File类与I/O操作

1 File类 1.1 File类概述 1.1.1 什么是File类 File是java.io包下作为文件和目录的类。File类定义了一些与平台无关的方法来操作文件,通过调用File类中的方法可以得到文件和目录的描述信息,包括名称、所在路径、读写性和长度等,还可以对文件…

力扣LCR 130. 衣橱整理(DFS 解法)

Problem: LCR 130. 衣橱整理 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 首先该问题可以归纳为一类遍历二维矩阵的题目,此类中的一部分题目可以利用DFS来解决,具体到本题目: 我们可以利用一个布尔类型的二维数组记录我们已经访…

LeetCode(65)LRU 缓存【链表】【中等】

目录 1.题目2.答案3.提交结果截图 链接: LRU 缓存 1.题目 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 k…

Vue3使用了Vite和UnoCSS导致前端项目启动报错:Error:EMFILE:too many open files

一个 Vue3 的项目,用的是 Vite 打包,通过 npm run dev 运行时,遇到了以下错误(尤其是引入了 Element-Plus 后): Error: EMFILE: too many open files,后面是具体的文件路径。。甚至到了 node_mo…

基于 Gin 的 HTTP 代理上网行为记录 demo

前言: 前端时间写了好几篇使用 Gin 框架来做 HTTP 代理 demo 的文章,然后就想着做一个记录上网行为的小工具,就是简单记录看看平时访问了什么网站(基于隧道代理的,不是中间人代理,所以只能记录去了哪里,不能…

vue3:直接修改reative的值,页面却不响应,这是什么情况?

目录 前言: 错误示范: reactive() 的局限性 解决办法: 1.使用ref 2.reative多套一层 3.使用Object.assign 前言: 今天看到有人在提问,问题是这样的,我修改了reative的值,数据居然失去了响…

详细了解stm32---按键

提示:永远支持知识文档免费开源,喜欢的朋友们,点个关注吧!蟹蟹! 目录 一、了解按键 二、stm32f103按键分析 三、按键应用 一、了解按键 同学们,又见面了o(* ̄▽ ̄*)ブ,最…

【Java代码审计】XSS篇

【Java代码审计】XSS篇 1.Java中XSS常见触发位置2.反射型XSS3.存储型XSS4.XSS漏洞修复 1.Java中XSS常见触发位置 XSS漏洞产生后必然会有相关的输入/输出,因此我们只需快速找到这些输入/输出点,即可快速地进行跟踪发现漏洞。输入在Java中通常使用“reque…

ES6 面试题 | 02.精选 ES6 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

C++试卷(华南理工大学)

华南理工大学期末考试 《高级语言程序设计(I)》A卷 注意事项: 1. 考前请将密封线内各项信息填写清楚; 2. 所有答案写在答题纸上,答在其它地方无效; 3.考试形式:闭卷&#xff1b…

LT7911D是TYPE-C/DP或者EDP转2 PORT MIPI和LVDS加音频

1.概述: T7911D是一款高性能TYPE-C/DP/EDP转2 PORT MIPI或者LVDS的芯片,目前主要在AR/VR或者显示器上应用的很多,对于DP1.2输入,LT7911D可配置为1/2/4车道。自适应均衡化使其适用于长电缆应用,最大带宽可达21.6Gbps。…

AI智能配音助手微信小程序前后端源码支持多种声音场景选择

大家好今天给大家带来一款配音小程序 ,这款小程序支持多种不同声音和场景的选择更人性化, 比如说支持各地区的方言,英文,童声呀等等、 另外也支持男声女声的选择,反正就是模板那些非常的多 当然啦音量,语调,语速那些都是可以DIY跳转的哟,所以说这一款小程…

【单元测试】Junit 4--junit4 内置Rule

1.0 Rules ​ Rules允许非常灵活地添加或重新定义一个测试类中每个测试方法的行为。测试人员可以重复使用或扩展下面提供的Rules之一,或编写自己的Rules。 1.1 TestName ​ TestName Rule使当前的测试名称在测试方法中可用。用于在测试执行过程中获取测试方法名称…