Redis基础篇12 — 使用命令(四)对 value 的操作命令

list 数据类型简述

Redis 当中的 list 就是指简单的字符串列表。当您使用 list 数据类型时,需要首先指定一个 key ,然后使用相关的命令从列表的 L(left,左) 和 R (right,右)添加元素,这些元素按照添加的先后顺序进行排列。一个列表可以拥有 2^32-1 个元素,当列表中的最后一个元素弹出时,该结构自动删除。

关于 list 底层数据结构的实现(有些资料也叫编码方式),随着版本的更替有所不同:

  • 早期版本使用 linkedlist(双端列表)和 ziplist(压缩列表)
  • 从 Redis 3.2 开启,使用 linkedlist + ziplist 组成的 quicklist。
  • 从 redis 7.0 开始,还是使用 quicklist,只不过将 ziplist 替换为 listpack

当列表中的元素较少时,Redis 会使用一块连续的内存来存储这些元素,这个连续的数据结构被称为 ziplist,此时的所有元素都是紧紧挨着一起存储。ziplist 是 Redis 为了节省内存而开发的,一个 ziplist 可以包含任意多的节点,每个节点都可以保存一个字符数组或整数值。当数据量较大时,Redis 会使用 quicklist 结构存储元素,之所以这么做,是因为当数据量大后,如果继续采用普通链表存储列表元素,带来的后果是:

  1. 压缩率不明显且修改数据的效率不高
  2. 占用且浪费了大量的内存空间
  3. 查询效率不高

可以从源代码中看到一些情况:

Shell > vim /usr/local/src/redis-7.2.1/src/quicklist.h
...
typedef struct quicklistNode {
    struct quicklistNode *prev;
    struct quicklistNode *next;
    unsigned char *entry;
    size_t sz;             /* entry size in bytes */
    unsigned int count : 16;     /* count of items in listpack */
    unsigned int encoding : 2;   /* RAW==1 or LZF==2 */
    unsigned int container : 2;  /* PLAIN==1 or PACKED==2 */
    unsigned int recompress : 1; /* was this node previous compressed? */
    unsigned int attempted_compress : 1; /* node can't compress; too small */
    unsigned int dont_compress : 1; /* prevent compression of entry that will be used later */
    unsigned int extra : 9; /* more bits to steal for future usage */
} quicklistNode;
...
typedef struct quicklist {
    quicklistNode *head;
    quicklistNode *tail;
    unsigned long count;        /* total count of all entries in all listpacks */
    unsigned long len;          /* number of quicklistNodes */
    signed int fill : QL_FILL_BITS;       /* fill factor for individual nodes */
    unsigned int compress : QL_COMP_BITS; /* depth of end nodes not to compress;0=off */
    unsigned int bookmark_count: QL_BM_BITS;
    quicklistBookmark bookmarks[];
} quicklist;

lpush 命令和 rpush 命令

这里的 lr 代表着往 head 的 L(left,左) 和 R(right,右)位置插入数据。

# 插入一些 list 数据
192.168.100.3:6379> select 2
OK
192.168.100.3:6379[2]> lpush cityname:china ShangHai BeiJing GuangZhou
(integer) 3

L 表示您往链表 head 的左侧插入,插入位置如下所示:

                               ----
GuangZhou  BeiJing  Shanghai  |head|
                               ----
# 您可以使用 `lrange` 命令查看顺序:
192.168.100.3:6379[2]> lrange cityname:china 0 -1
1) "GuangZhou"
2) "BeiJing"
3) "ShangHai"

# 如果使用 `rpush` 命令插入数据,表示往链表 head 右侧插入数据。再使用 `lrange` 查看顺序:
192.168.100.3:6379[2]>  rpush cityid:china 35270 46950 12045
(integer) 3
192.168.100.3:6379[2]> LRANGE cityid:china 0 -1
1) "35270"
2) "46950"
3) "12045"

llen 命令

查看单个 key 当中 list 数据类型的元素数量

192.168.100.3:6379[2]>  llen cityname:china
(integer) 3

lrange 命令

指定范围获取 list 内的元素。按照从左到右的位置规则,0 表示第一个元素,1 表示第二个元素,以此类推;按照从右到左的位置规则,-1 表示倒数的第一个元素,-2 表示倒数第二个元素,以此类推。

192.168.100.3:6379[2]>  lrange cityid:china -2 -1
1) "46950"
2) "12045"

lindex 命令

指定一个索引(索引号)获取 list 当中的单个元素。按照从左到右的位置规则,第一个元素的索引为 0,第二个索引为 1,以此类推;按照从右到左的位置规则,第一个元素的索引为 -1,第二个元素为 -2,以此类推。

192.168.100.3:6379[2]> LINDEX cityname:china 0
"GuangZhou"

192.168.100.3:6379[2]> LINDEX cityname:china 1
"BeiJing"

192.168.100.3:6379[2]> LINDEX cityname:china 2
"ShangHai"

# 元素不存在时返回 nil
192.168.100.3:6379[2]> LINDEX cityname:china 3
(nil)

192.168.100.3:6379[2]> LINDEX cityname:china -1
"ShangHai"

192.168.100.3:6379[2]> LINDEX cityname:china -2
"BeiJing"

192.168.100.3:6379[2]> LINDEX cityname:china -3
"GuangZhou"

lset 命令

通过指定一个索引来修改单个元素。

192.168.100.3:6379[2]> lrange cityname:china 0 -1
1) "GuangZhou"
2) "BeiJing"
3) "ShangHai"

192.168.100.3:6379[2]> lindex cityname:china 0
"GuangZhou"

192.168.100.3:6379[2]> lset cityname:china 0 GZ
OK

192.168.100.3:6379[2]> lindex cityname:china 0
"GZ"

lpushx 命令和 rpushx 命令

x 表示仅当 list 存在时,才往里面追加一个或多个元素。

192.168.100.3:6379[2]> rpushx cityname:china ChongQing  HangZhou
(integer) 5

192.168.100.3:6379[2]> lrange cityname:china 0 -1
1) "GZ"
2) "BeiJing"
3) "ShangHai"
4) "ChongQing"
5) "HangZhou"

linsert 命令

在一个元素的前面或后面插入一个元素。前面与后面对应的关键字是 beforeafter。比如要在 ChongQing 元素的前面加入 ShenZhen

192.168.100.3:6379[2]> linsert cityname:china before ChongQing ShenZhen
(integer) 6

192.168.100.3:6379[2]> LRANGE cityname:china 0 -1
1) "GZ"
2) "BeiJing"
3) "ShangHai"
4) "ShenZhen"
5) "ChongQing"
6) "HangZhou"

lpop 命令 和 rpop 命令

pop 表示弹出元素(或移除元素)。当 list 剩余的最后一个元素被弹出后,list(key) 就被会删除。

  • 当使用 lpop 命令时,count 表示从左到右弹出的元素个数,必须为正整数,不指定 count,表示弹出第一个元素。
  • 当使用 rpop 命令时,count 表示从右到左弹出的元素个数,必须为正整数,不指定 count,表示弹出最后面的一个元素。
# 如果不指定 count,则弹出第一个元素
192.168.100.3:6379[2]> lpop cityname:china
"GZ"

192.168.100.3:6379[2]> lrange cityname:china 0 -1
1) "BeiJing"
2) "ShangHai"
3) "ShenZhen"
4) "ChongQing"
5) "HangZhou"

# 将 BeiJing 和 ShangHai 弹出
192.168.100.3:6379[2]>  lpop cityname:china 2
1) "BeiJing"
2) "ShangHai"

192.168.100.3:6379[2]> lrange cityname:china 0 -1
1) "ShenZhen"
2) "ChongQing"
3) "HangZhou"

# 将最后面的一个元素弹出
192.168.100.3:6379[2]> rpop cityname:china
"HangZhou"

192.168.100.3:6379[2]> lrange cityname:china 0 -1
11) "ShenZhen"
12) "ChongQing"

# 将剩余的两个元素弹出,list 被删除
192.168.100.3:6379[2]> lpop cityname:china 2
13) "ShenZhen"
14) "ChongQing"

192.168.100.3:6379[2]> keys *
1) "cityid:china"

blpop 命令和 brpop 命令

命令中的 b 表示 blocking。基本用法如下所示:

192.168.100.3:6379[2]> help blpop

    BLPOP key [key ...] timeout
    summary: Removes and returns the first element in a list. Blocks until an element is available otherwise. Deletes the list if the last element was popped.
    since: 2.0.0
    group: list

192.168.100.3:6379[2]> help brpop

    BRPOP key [key ...] timeout
    summary: Removes and returns the last element in a list. Blocks until an element is available otherwise. Deletes the list if the last element was popped.
    since: 2.0.0
    group: list
  • blpop 命令:针对 list 数据类型,对 list 第一个元素定义超时时间,当到达了超时时间,第一个元素弹出。当 list 剩余的最后一个元素被弹出后,list(key) 就被会删除。时间单位为秒。
  • brpop 命令:针对 list 数据类型,对 list 最后面的一个元素定义超时时间,当到达了超时时间,最后面的一个元素弹出。当 list 剩余的最后一个元素被弹出后,list(key) 就被会删除。时间单位为秒。

若您给定了多个 key ,则按照给定 key 的先后顺序依次检查 list。

# 添加一些 list 数据
192.168.100.3:6379[2]> rpush name:first zhang wang wu li
(integer) 4

192.168.100.3:6379[2]> lrange name:first 0 -1
1) "zhang"
2) "wang"
3) "wu"
4) "li"

# 使用示例
192.168.100.3:6379[2]> blpop name:first  10
1) "name:first"
2) "zhang"

192.168.100.3:6379[2]> lrange name:first 0 -1
1) "wang"
2) "wu"
3) "li"

192.168.100.3:6379[2]> brpop name:first 15
1) "name:first"
2) "li"

192.168.100.3:6379[2]> lrange name:first 0 -1
1) "wang"
2) "wu"

# 若您针对一个不存在的 key ,则会阻塞 5 秒或者直到发现有 key 存在且有可被弹出的元素:
192.168.100.3:6379[2]> blpop name 5
(nil)
(5.04s)

rpoplpush 命令

针对两个 key 且它们都是 list 数据类型,将源 key(source key) 的最后面一个元素弹出,并将该元素插入到目标 key (destination key)的最左边。

192.168.100.3:6379[2]> keys *
1) "cityid:china"
2) "name:first"

192.168.100.3:6379[2]> rpoplpush name:first cityid:china
"wu"

192.168.100.3:6379[2]> lrange name:first 0 -1
1) "wang"

192.168.100.3:6379[2]> lrange cityid:china 0 -1
1) "wu"
2) "35270"
3) "46950"
4) "12045"

lrem 命令

从 list 中删除元素。若 list 剩余的最后一个元素被删除,list(key) 就被会删除。用法为:

192.168.100.3:6379[2]> help lrem

    LREM key count element
    summary: Removes elements from a list. Deletes the list if the last element was removed.
    since: 1.0.0
    group: list

count 的取值有这么几种情况:

  • count > 0。表示从左到右进行搜索,删除与用户指定元素相等的元素,删除的数量为 count 指定的数量
  • count = 0。表示删除所有与用户指定元素相等的元素。
  • count < 0。表示右到左进行搜索,删除与用户指定元素相等的元素,删除的数量为 count 的绝对值
# 追加两个元素
192.168.100.3:6379[2]> rpushx cityid:china wu 35270
(integer) 6

192.168.100.3:6379[2]> lrange cityid:china 0 -1
1) "wu"
2) "35270"
3) "46950"
4) "12045"
5) "wu"
6) "35270"

# 使用 `lrem` 命令
192.168.100.3:6379[2]> lrem cityid:china 1 wu
(integer) 1

192.168.100.3:6379[2]> lrange cityid:china 0 -1
1) "35270"
2) "46950"
3) "12045"
4) "wu"
5) "35270"

192.168.100.3:6379[2]> lrem cityid:china 0 35270
(integer) 2

192.168.100.3:6379[2]> lrange cityid:china 0 -1
1) "46950"
2) "12045"
3) "wu"

ltrim 命令

对 list 中的元素进行修剪,即只保留用户定义的索引区间的元素,删除索引区间之外的任何元素。按照从左到右的位置规则,第一个元素的索引为 0,第二个索引为 1,以此类推;按照从右到左的位置规则,第一个元素的索引为 -1,第二个元素为 -2,以此类推。

# 追加3个元素
192.168.100.3:6379[2]> rpushx name:first cao qian shun yao
(integer) 5

192.168.100.3:6379[2]> lrange name:first 0 -1
1) "wang"
2) "cao"
3) "qian"
4) "shun"
5) "yao"

# 现只想保留 cao、qian、shun这三个元素,则
192.168.100.3:6379[2]> LTRIM name:first 1 3
OK

192.168.100.3:6379[2]> lrange name:first 0 -1
1) "cao"
2) "qian"
3) "shun"
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇