Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >redis系列:通过队列案例学习list命令

redis系列:通过队列案例学习list命令

原创
作者头像
云枭
发布于 2018-08-16 13:53:43
发布于 2018-08-16 13:53:43
1.5K0
举报
文章被收录于专栏:fixzdfixzd

前言

这一篇文章将讲述Redis中的list类型命令,同样也是通过demo来讲述,其他部分这里就不在赘述了。

项目Github地址:https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-list

案例

demo功能是队列,整个demo的大致页面如下。左边是存储到Redis中的数据,右边是从Redis中弹出的数据。

准备工作

首先定义一个存储list的key

代码语言:txt
AI代码解释
复制
private static final String LIST_KEY = "list:1";

队列的key就用list:1

redis操作对象

代码语言:txt
AI代码解释
复制
private RedisTemplate redisTemplate;
//string 命令操作对象
private ValueOperations valueOperations;
//list 命令操作对象
private ListOperations listOperations;

list在Redis中的结构可以看下图(图片来源于Redis in Action)。

图片来源于Redis in Action
图片来源于Redis in Action

插入数据

头部插入
命令介绍

命令

用例

描述

LPUSH

LPUSH key value value ...

将所有指定的值插入到存于 key 的列表的头部。 如果 key 不存在,那么在进行 push 操作前会创建一个空列表。

LPUSHX

LPUSHX key value

只有当 key 已经存在并且存着一个 list 的时候,在这个 key 下面的 list 的头部插入 value。

接下来看看demo中头部插入的功能,点击下图中头部插入按钮,然后在弹出框中填入数字0,点击提交后整个头部插入流程结束。可以看到左边的队列数据出现了一条{"data":"0"} 数据,在数据{"data":"1"} 上面。

来看看后台的方法

代码语言:txt
AI代码解释
复制
@RequestMapping(value = "/leftPop",method = RequestMethod.GET)
public Object leftPop(){
    return listOperations.leftPop(LIST_KEY);
}

如果需要在Redis中操作,可以敲下面的命令

代码语言:txt
AI代码解释
复制
lpush list:1 "{\"data\":\"0\"}" 
尾部插入
命令介绍

命令

用例

描述

RPUSH

RPUSH key value value ...

向存于 key 的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。

RPUSHX

RPUSHX key value

将值 value 插入到列表 key 的表尾, 当且仅当 key 存在并且是一个列表。

接下来看看demo中尾部插入的功能,点击下图中尾部插入按钮,然后在弹出框中填入数字11,点击提交后整个新增流程结束。可以看到左边的队列数据出现了一条{"data":"11"} 数据,在数据{"data":"10"}下面。

来看看后台的方法

代码语言:txt
AI代码解释
复制
@RequestMapping(value = "/rightPop",method = RequestMethod.GET)
public Object rightPop(){
    return listOperations.rightPop(LIST_KEY);
}

如果需要在Redis中操作,可以敲下面的命令

代码语言:txt
AI代码解释
复制
rpush list:1 "{\"data\":\"11\"}" 

列表查询

命令介绍

同样先看看相关的获取值命令

命令

用例

描述

LRANGE

LRANGE key start stop

返回存储在 key 的列表里指定范围内的元素。

LINDEX

LINDEX key index

返回列表里的元素的索引 index 存储在 key 里面。

LLEN

LLEN key

返回存储在 key 里的list的长度。

后台查询方法,将新增的内容查询出来

代码语言:txt
AI代码解释
复制
@RequestMapping(value = "/getList",method = RequestMethod.GET)
public List getList(){
    List list = listOperations.range(LIST_KEY, 0, -1);

    //可以用size获取成员长度
    //listOperations.size(LIST_KEY);

    return list;
}

数据弹出

头部弹出

命令

用例

描述

LPOP

LPOP key

移除并且返回 key 对应的 list 的第一个元素。

BLPOP

BLPOP key key ... timeout

它是命令 LPOP 的阻塞版本,这是因为当给定列表内没有任何元素可供弹出的时候, 连接将被 

 命令阻塞。

接下来看看头部弹出的功能,点击下图中头部弹出按钮,可以看到左边的队列顶部数据减少了,在右边弹出的数据出现了左边队列数据消失的数据。

来看看后台的方法

代码语言:txt
AI代码解释
复制
@RequestMapping(value = "/leftPop",method = RequestMethod.GET)
public Object leftPop(){
    return listOperations.leftPop(LIST_KEY);
}

如果需要在Redis中操作,可以敲下面的命令

代码语言:txt
AI代码解释
复制
lpop list:1 
尾部弹出

命令

用例

描述

RPOP

RPOP key

移除并返回存于 key 的 list 的最后一个元素。

BRPOP

BRPOP key key ... timeout

它是 RPOP 的阻塞版本,因为这个命令会在给定list无法弹出任何元素的时候阻塞连接。

接下来看看尾部弹出的功能,点击下图中尾部弹出按钮,可以看到左边的队列尾部数据减少了,在右边弹出的数据出现了左边队列数据消失的数据。

来看看后台的方法

代码语言:txt
AI代码解释
复制
@RequestMapping(value = "/rightPop",method = RequestMethod.GET)
public Object rightPop(){
    return listOperations.rightPop(LIST_KEY);
}

如果需要在Redis中操作,可以敲下面的命令

代码语言:txt
AI代码解释
复制
rpop list:1 

其他命令

命令

用例

描述

LINSERT

LINSERT key BEFORE|AFTER pivot value

把 value 插入存于 key 的列表中在基准值 pivot 的前面或后面。

LREM

LREM key count value

从存于 key 的列表里移除前 count 次出现的值为 value 的元素。

LSET

LSET key index value

设置 index 位置的list元素的值为 value。

LTRIM

LTRIM key start stop

修剪(trim)一个已存在的 list,这样 list 就会只包含指定范围的指定元素。

RPOPLPUSH

RPOPLPUSH source destination

原子性地返回并移除存储在 source 的列表的最后一个元素(列表尾部元素), 并把该元素放入存储在 destination 的列表的第一个元素位置(列表头部)。

BRPOPLPUSH

BRPOPLPUSH source destination timeout

BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本。

RPOPLPUSH和BRPOPLPUSH

这两个命令作用其实是相同的,只不过BRPOPLPUSH是阻塞的,当没有数据时,会一直阻塞,直到有数据。

在Redis官方文档中,用RPOPLPUSH命令举了两个例子,一个是Reliable queue(安全的队列 ),另一个是Circular list(循环列表)。

Reliable queue(安全的队列 )

Redis通常都被用做一个处理各种后台工作或消息任务的消息服务器。 一个简单的队列模式就是:生产者把消息放入一个列表中,等待消息的消费者用 RPOP 命令(用轮询方式), 或者用 BRPOP 命令(如果客户端使用阻塞操作会更好)来得到这个消息。

然而,因为消息有可能会丢失,所以这种队列并是不安全的。例如,当接收到消息后,出现了网络问题或者消费者端崩溃了, 那么这个消息就丢失了。

RPOPLPUSH (或者其阻塞版本的 BRPOPLPUSH) 提供了一种方法来避免这个问题:消费者端取到消息的同时把该消息放入一个正在处理中的列表。 当消息被处理了之后,该命令会使用 LREM 命令来移除正在处理中列表中的对应消息。

另外,可以添加一个客户端来监控这个正在处理中列表,如果有某些消息已经在这个列表中存在很长时间了(即超过一定的处理时限), 那么这个客户端会把这些超时消息重新加入到队列中。

翻译来自 http://www.redis.cn/commands/rpoplpush.html

Circular list(循环列表)

RPOPLPUSH 命令的 source 和 destination 是相同的话, 那么客户端在访问一个拥有n个元素的列表时,可以在 O(N) 时间里一个接一个获取列表元素, 而不用像 LRANGE 那样需要把整个列表从服务器端传送到客户端。

上面这种模式即使在以下两种情况下照样能很好地工作: 有多个客户端同时对同一个列表进行旋转(rotating):它们会取得不同的元素,直到列表里所有元素都被访问过,又从头开始这个操作。 有其他客户端在往列表末端加入新的元素。

这个模式让我们可以很容易地实现这样一个系统:有 N 个客户端,需要连续不断地对一批元素进行处理,而且处理的过程必须尽可能地快。 一个典型的例子就是服务器上的监控程序:它们需要在尽可能短的时间内,并行地检查一批网站,确保它们的可访问性。

值得注意的是,使用这个模式的客户端是易于扩展(scalable)且安全的(reliable),因为即使客户端把接收到的消息丢失了, 这个消息依然存在于队列中,等下次迭代到它的时候,由其他客户端进行处理。

翻译来自 http://www.redis.cn/commands/rpoplpush.html

案例-约瑟夫问题

约瑟夫问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环

人们站在一个等待被处决的圈子里。 计数从圆圈中的指定点开始,并沿指定方向围绕圆圈进行。 在跳过指定数量的人之后,执行下一个人。 对剩下的人重复该过程,从下一个人开始,朝同一方向跳过相同数量的人,直到只剩下一个人,并被释放。

问题即,给定人数、起点、方向和要跳过的数字,选择初始圆圈中的位置以避免被处决。

来自维基百科 https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98

思路

定义一个list key为josephus,利用

代码语言:txt
AI代码解释
复制
RPOPLPUSH  josephus josephus

命令来构造循环链表,每当数到3时,使用rpop

代码语言:txt
AI代码解释
复制
rpop josephus

命令弹出

代码实现
代码语言:txt
AI代码解释
复制
public class JosephusProblem extends RedisBaseConnection {

    @Test
    public void test() {
        //构造数据
        for (int i = 1; i <= 41; i++) {
            listOperations.leftPush("josephus", String.valueOf(i));
        }

        int index = 1;
        while (listOperations.size("josephus") > 0) {
            //当数到3时,弹出
            if (index == 3) {
                System.out.println(listOperations.range("josephus", 0, -1));
                System.out.println("当前被杀的人是:" + listOperations.rightPop("josephus"));
                index = 0;
            } else {
                listOperations.rightPopAndLeftPush("josephus", "josephus");
            }
            index++;
        }
    }
}

整个代码步骤如下

  1. 先是模拟有41个人(向redis中key为josephus的list添加41个数据)
  2. 定义索引index
  3. 循环判断key为josephus的数据长度是否大于0
  4. 当索引index为3时,调用Redis的rpop命令弹出对应的数据。索引index不为3时,调用RPOPLPUSH命令,将对应的数据放到队列头部
  5. 索引index加1

运行结果有点长,这里只截图最后一部分的结果,如下

约瑟夫问题代码请点击JosephusProblem.java


建议学习的人最好每个命令都去敲下,加深印象。下面诗句送给你们。

纸上得来终觉浅,绝知此事要躬行。————出自《冬夜读书示子聿》

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
redis | 五、redis之List
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
雨中散步撒哈拉
2022/09/21
1K0
Redis教程06(List类型命令介绍)
列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边) 一个列表最多可以包含 2E32 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
用户4919348
2019/04/02
4700
【Redis】五大常见的数据类型之 List
我们都知道 Redis 提供了丰富的数据类型,常见的有五种:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)。
sidiot
2023/08/31
2380
【Redis】五大常见的数据类型之 List
Redis数据类型之List列表类型
list类型其实就是一个双向链表。通过push,pop操作从链表的头部或者尾部添加删除元素。 这使得list既可以用作栈,也可以用作队列。 上进上出 :栈 ,特点:数据 先进后出
兮动人
2021/06/11
5810
Redis数据类型之List列表类型
Redis 竟然能用 List 实现消息队列
分布式系统中必备的一个中间件就是消息队列,通过消息队列我们能对服务间进行异步解耦、流量消峰、实现最终一致性。
落寞的鱼丶
2022/02/22
2.1K0
Redis命令详解:Lists
List是Redis的基础数据类型之一,类似于Java中的LinkedList。一个列表最多包含232个元素,常被用作模拟队列操作,接下来我们具体介绍一下List相关的命令。
Jackeyzhe
2020/03/11
3610
Redis 列表(List)
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
子润先生
2021/07/05
7670
Redis 列表(Lists) 复习
Redis中的Lists相当于双向列表,实现原理是一个双向链表(其底层是一个快速列表),即可以支持反向查找和遍历,更方便操作。插入和删除操作非常快,时间复杂度为o(1),但是索引定位很慢,时间复杂度为o(n)。Redis set 类型中成员不能重复。
陈大剩博客
2023/03/06
3530
redis命令之操作列表
Reids是可以操作列表的,列表是一种数据结构,在redis中,它允许用户从列表的两端推入或者弹出数据、获取列表数据以及执行各种常见的列表操作。初次之外,列表还可以用来存储任务信息、最近浏览过的文章或者常用联系人信息,或者是用来消息队列当中。
OECOM
2020/07/01
6650
4.Redis常用命令:List
  在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295。       从元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将会是非常高效的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完
陈树义
2018/04/13
6400
Redis-05Redis数据结构--链表( linked-list)
由于是双向链表,所以只能够从左到右,或者从右到左地访问和操作链表里面的数据节点。 但是使用链表结构就意味着读性能的丧失,所以要在大量数据中找到一个节点的操作性能是不佳的,因为链表只能从一个方向中去遍历所要节点,比如从查找节点 10000 开始查询,它需要按照节点1 、节点 2、节点 3……直至节点 10000,这样的顺序查找,然后把一个个节点和你给出的值比对,才能确定节点所在。如果这个链表很大,如有上百万个节点,可能需要遍历几十万次才能找到所需要的节点,显然查找性能是不佳的。
小小工匠
2021/08/17
6970
Redis初识~List命令
List命令 Redis的列表允许用户从序列的两端推入元素或者弹出元素。可以来创建常见的队列信息。 List常用命令 blpop: 列表阻塞式弹出。当在查询如果指定得key 都是空列表那么会一直等待。如果存在得key中有值那么会取出值来。不建议放在事务中MULTI/EXEC中。时间复杂度为O(1)。模式:事件提醒。为了等待一个元素得到达列表中会采用轮询得方式来进行探查。另一种好得方式是使用阻塞原语。在新元素没有到达得时候阻塞住,避免轮询占用资源。blpop key key key timeout
用户2196435
2018/07/19
5920
redis中List命令的基础操作
获取列表在给定范围内的所有元素: [“Shanghai”, “Guangzhou”, “Shenzhen”]。
GeekLiHua
2025/01/21
880
Redis五大数据类型之List操作命令
移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
别团等shy哥发育
2023/02/25
4910
Redis五大数据类型之List操作命令
Redis之List类型解读
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
一个风轻云淡
2023/10/15
2710
Redis之List类型解读
Redis 实现安全队列
Redis的列表数据结构可以让我们方便的实现消息队列 例如用 LPUSH(BLPUSH)把消息入队,用 RPOP(BRPOP)获取消息 绝大部分的情况下,这些操作都是没问题的,但并不能保证绝对安全 当 LPOP 返回一个元素给客户端的时候,会从 list 中把该元素移除,这意味着该元素就只存在于客户端的上下文中,如果客户端在处理这个返回元素的过程崩溃了,那么这个元素就永远丢失了 如何解决? redis 有一个 RPOPLPUSH (或者其阻塞版本的 BRPOPLPUSH)命令 命令格式 RPO
dys
2018/04/03
1.4K0
程序员过关斩将--redis做消息队列,香吗?
在程序员这个圈子打拼了太多年,见过太多的程序员使用redis,其中一部分喜欢把redis做缓存(cache)使用,其中最典型的当属存储用户session,除此之外,把redis作为消息队列使用也不在少数,可见redis在互联网中应用是多么的广泛。
架构师修行之路
2020/02/24
5970
Redis之List类型解读
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
一个风轻云淡
2023/09/22
2650
Redis实践:构建高效消息队列与深入解析BRPOP命令
Redis, 作为一种高性能的键值存储系统,通过提供丰富的数据结构和操作,被广泛应用于各种场景中,包括作为消息队列的实现工具。消息队列是一种在消息的发送者和接收者之间建立的、存储消息的容器,用于异步处理和传输数据,以及分离处理过程。下面列举了Redis中实现消息队列的一些关键功能和操作。
运维开发王义杰
2024/04/15
1.3K0
Redis实践:构建高效消息队列与深入解析BRPOP命令
Redis 队列
举例: 队列主要用在系统解耦、流量削峰、异步处理、数据顺序处理等场景。新手在使用时可能会犯一些常见的错误。下面讲一个新手容易犯的错误,在这个示例中把队列的入队、出队和Redis存储节点的主从关系给混淆了,示例如下
高广超
2018/12/12
1.8K0
相关推荐
redis | 五、redis之List
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档