Loading

redis-05 五大基本类型之List

redis-05 五大基本类型之List

概述

Redis 中的 List 可以存储一个有序的字符串(存储的内容只能是字符串!)列表,由于可以对列表同时进行操作,这使得它同时具备了 stack 和 queue 的特性。

Redis 中的列表类型是通过双向链表实现的,所以查和改两端快,中间慢。

Redis 的集合数据类型都不支持嵌套,列表里面不能存储列表等其它元素,集合里面不能存储列表而只能存储字符串。


命令

增、删

  • lpush
    • 在链表左侧添加一个元素
  • rpop
    • 弹出链表右侧的一个元素
@Test
public void pushAndPop() {
    long len = j.lpush("numbers", "1", "2", "3");
    assertEquals(3L, len);
    // 3, 2, 1

    len = j.rpush("numbers", "4", "5", "6");
    assertEquals(6L, len);
    // 3, 2, 1, 4, 5, 6

    String number = j.lpop("numbers");
    assertEquals("3", number);

    number = j.rpop("numbers");
    assertEquals("6", number);
}

截取链表

  • llen
    • 获取链表长度
  • lrange
    • 截取指定位置的链表
  • lrem
    • 移出指定个数的指定值的链表元素
@Test
public void subListAndLen() {
    long len = j.lpush("numbers", "1", "2", "3");
    assertEquals(3L, len);
    // 3, 2, 1

    len = j.rpush("numbers", "4", "5", "6");
    assertEquals(6L, len);
    // 3, 2, 1, 4, 5, 6

    len = j.llen("numbers");
    assertEquals(6L, len);

    List<String> numbers = j.lrange("numbers", 1L, 4L);
    assertEquals(4, numbers.size());
    assertEquals("2", numbers.get(0));

    // 顺序永远只能是从左向右
    List<String> numbers1 = j.lrange("numbers", -3L, -1L);
    // 3, 5, 6
    assertEquals("4", numbers1.get(0));

    // 当第二个参数 count > 0 时,删除所有匹配元素,负数和正数则会分别
    // 从左到右或者从右到左删除指定个匹配的元素
    long effected = j.lrem("numbers", 0, "1");
    assertEquals(1L, effected);
}

链表倒腾

  • rpoplpush
    • 顾名思义
    • 弹一个、加一个
@Test
public void listElementTransfer() {
    long len = j.lpush("numbers", "1", "2", "3");
    assertEquals(3L, len);
    // 3, 2, 1

    len = j.rpush("numbers", "4", "5", "6");
    assertEquals(6L, len);
    // 3, 2, 1, 4, 5, 6

    String number = j.rpoplpush("numbers", "newNumbers");
    assertEquals("6", number);

    number = j.rpoplpush("numbers", "newNumbers");
    assertEquals("5", number);

    List<String> newNumbers = j.lrange("newNumbers", 0, -1);
    assertNotNull(newNumbers);
    assertEquals(2, newNumbers.size());
    assertEquals("5", newNumbers.get(0));
    assertEquals("6", newNumbers.get(1));

    // You can also use this command to move the last element to the front of list in the same list
}

按址操作

按址改值

  • lindex
    • 获取指定下标的元素
    • 下标越界返回 nil(null)
  • lset
    • 设置指定下标的元素的值
    • 下标越界抛出异常
@Test
public void getAndSetListValueByIndex() {
    long len = j.lpush("numbers", "1", "2", "3");
    assertEquals(3L, len);
    // 3, 2, 1

    len = j.rpush("numbers", "4", "5", "6");
    assertEquals(6L, len);
    // 3, 2, 1, 4, 5, 6

    String number_2 = j.lindex("numbers", 1L);
    assertEquals("2", number_2);

    // 下标越界会返回 null
    String number_7 = j.lindex("numbers", 7L);
    assertNull(number_7);

    String status = j.lset("numbers", 4L, "55");
    assertEquals("OK", status);

    String number_4 = j.lindex("numbers", 4L);
    assertEquals("55", number_4);

    try {
        number_7 = j.lset("numbers", 7L, "77");
        assertNull(number_7);
    } catch (JedisDataException e) {
        System.err.println(e);
    }
}
// 执行结果
// redis.clients.jedis.exceptions.JedisDataException: ERR index out of range

trim 操作

  • trim
    • 截取制定位置的链表元素
    • 原链表发生改变
@Test
public void lTrim() {
    long len = j.lpush("numbers", "1", "2", "3");
    assertEquals(3L, len);
    // 3, 2, 1

    len = j.rpush("numbers", "4", "5", "6");
    assertEquals(6L, len);
    // 3, 2, 1, 4, 5, 6

    String status = j.ltrim("numbers", 1L, 4L);
    // 2, 1, 4, 5
    assertEquals("OK", status);

    List<String> numbers = j.lrange("numbers", 0, -1);
    assertNotNull(numbers);
    assertEquals(4, numbers.size());
    assertEquals("2", numbers.get(0));
    assertEquals("1", numbers.get(1));
    assertEquals("4", numbers.get(2));
    assertEquals("5", numbers.get(3));
}

按值操作

链表插入

  • linsert
    • 指定值的指定位置插入热定值
@Test
public void insertIntoList() {
    long len = j.lpush("numbers", "1", "2", "3");
    assertEquals(3L, len);
    // 3, 2, 1

    len = j.rpush("numbers", "4", "5", "6");
    assertEquals(6L, len);
    // 3, 2, 1, 4, 5, 6

    len = j.linsert("numbers", ListPosition.AFTER, "2", "8");
    assertEquals(7L, len);
    // 3, 2, 8, 1, 4, 5, 6

    len = j.linsert("numbers", ListPosition.BEFORE, "1", "7");
    assertEquals(8L, len);

    String number_3 = j.lindex("numbers", 3);
    assertEquals("7", number_3);
}

实践

存储文章 ID 列表

我们使用一个 posts:list 来记录文章 ID 列表。这样一来分页操作就变得非常简单了(在这里不做演示)。


存储文章评论

由于评论一般不具备可修改性,所以能直接将评论对象序列化后存储在对应的文章评论列表中。

posted @ 2021-10-06 00:13  槐下  阅读(92)  评论(0编辑  收藏  举报