在前几篇我们介绍了Redis类型中的字符串类型和哈希类型,今天我们了解一下Redis中的列表类型。在Redis中列表类型,可以简单的理解为存储多个有序字符串的一种新类型,这种类型除了字符串类型中已有的功能外,还提供了其它的功能。如可以对列表的两端插入和弹出元素(在列表中的字符串都可以称之为元素),除此之外还可以获取指定的元素列表,并且还可以通过索引下标获取指定元素等等。下面我们通过下图来看一下Redis中列表类型的插入和弹出操作:

img

下面我们看一下Redis中列表类型的获取与删除操作:

img

下面我们看一下Redis列表类型的特点:

  • 列表中所有的元素都是有序的。所以在Redis中列表类型是可以通过索引获取的,也就是上图中的
lindex命令

并且在Redis中列表类型的索引是从0开始的。

  • 列表中的元素是可以重复的。也就是说在Redis列表类型中,是可以保存重复的元素,也就是如下图所示:

img

下面我们还是和学习其它数据类型一样,我们还是先学习一下Redis列表类型的命令。

命令

一、添加操作

1.从右边插入元素

rpush key value [value ...]

img

我们看rpush命令在插入时,是有返回值的,返回值的数量就是当前列表中所有元素的个数。

我们也可以用下面的命令从左到右获取当前列表中的所有的元素,也就是如上图所示中那样。

lrange 0 -1 

2.从左边插入元素

lpush key value [value ...]

img

lpush命令的返回值及用法和rpush命令一样,这里就不在介绍了,但通过上面的事例证明了我们前面说的,因为当前key中已经有了3个元素了,所以我们在执行插入命令时,返回的就是6而不是3,因为rpush命令和lpush命令的返回值并不是当前插入元素的个数,而返回的是当前key中全部元素的个数。


3.向某个元素前或者后插入元素

linsert key BEFORE|AFTER pivot value

img

linsert命令在执行的时候首先会从当前列表中查找到pivot元素,其次在将这个新元素插入到pivot元素的前面或者后面。并且我们通过上图所示知道linsert命令在执行成功后也是会有返回值的,返回的结果就是当前列表中元素的个数。


二、查找

1.获取指定范围内的元素列表

lrange key start stop

img

lrange命令会获取列表中指定索引范围的所有元素。通过索引获取列表主要有两个特点:

  • 索引下标从左到右分别是0到N-1,从右到左是-1到-N。
  • lrange命令中的end参数在执行时会包括当前元素的。并不是所有的语言都是这样的。如我们要获取列表中前两个元素则可以如下图所示:

img

2.获取列表中指定索引下标的元素

lindex key index

img


3.获取列表长度

llen key

img


三、删除

1.从列表左侧弹出元素

lpop key

img

lpop命令执行成功后会返回当前被删除的元素名称。


2.从列表右侧弹出元素

rpop key

img

rpop命令和lpop命令的使用方式一样,这里不在做过多介绍了。


3.删除指定元素

lrem key count value

lrem命令会将列表中等于value的元素删除掉,并且会根据count参数,来决定删除value的元素个数。下面我们看一下count参数的使用说明:

  • count > 0:表示从左到右,最多删除count个元素。也就是如下图所示:

img
我们看上图中的命令中,虽然我们将count参数指定的是5,将value参数指定的是2,但由于当前列表中只有一个2,所以,当前lrem命令最多只能删除1个元素,并且lrem命令也是有返回值的,也就是当前成功删除元素的个数。
img

  • count < 0:从右到左,最多删除count个元素。

img

  • count = 0:删除所有元素。

img


4.按照索引范围修剪列表

ltrim key start stop

ltrim命令会直接保留start索引到stop索引的之间的元素,并包括当前元素,而之外的元素则都会删除掉,所以该命令也叫修剪列表。

img

并且有一点要注意ltrim命令不会返回当前的列表中元素的个数,而是返回改命令是否成功的状态。


四、修改

1.修改指定索引下标的元素

lset key index value

img


五、阻塞操作

blpop key [key ...] timeout
brpop key [key ...] timeout

blpop和brpop命令是lpop和rpop命令的阻塞版本,它们除了弹出方向不同以外,使用方法基本相同。

  • key [key ...]:可以指定多个列表的键。
  • timeout:阻塞时间(单位:秒)

下面我们看一下该命令的详细使用。

  1. 列表为空:如果timeout=3,则表示客户端等待3秒后才能返回结果,如果timeout=0,则表示客户端会一直等待,也就是会阻塞。

img
由于我期间向列表中插入了元素,否则上述命令将一直阻塞下去。
2.列表不为空:如果timeout=0,并且列表不为空时,则blpop和brpop命令会立即返回结果,不会阻塞。
img


下面我们看一下blpop和brpop命令的注意事项。

  • 如果使用blpop和brpop命令指定多个键时,blpop和brpop命令会从左到右遍历键,并且一旦有一个键能返回元素,则客户端会立即返回。

img
当列表为空时,上述命令会阻塞,如果向上述中的任何一个键中插入元素,则上述命令会直接返回该键的元素。

  • 如果多个客户端都对同一个键执行blpop或者brpop命令,则最先执行该命令的客户端会获取到该键的元素。

img
我同时启动了3个客户端,因为当前列表为空,所以上述命令执行后会阻塞。如果此时我向该列表中插入元素,则只有第一个客户端会有返回结果,因为第一个客户端是第一个执行上述命令的。
img
img


下面我们看一下列表中命令的相关时间复杂度。

操作类型 命令 时间复杂度
添加 rpush key value [value ...] O(k),k是元素的个数
添加 lpush key value [value ...] O(k),k是元素的个数
添加 linsert key BEFORE/AFTER pivot value O(n),n是pivot距离列表头或者尾的距离
添加 lrange key start stop O(s + n),s是start偏移量,n是start到stop的范围
添加 lindex key index O(n),n是索引的偏移量
添加 llen key O(1)
添加 lpop key O(1)
添加 rpop key O(1)
添加 lrem key count value O(n),n是列表长度
添加 ltrim key start stop O(n),n是要裁剪的元素个数
添加 lset key index value O(n),n是索引的偏移量
添加 blpop/brpop key [key ...] timeout O(1)

内部编码

列表中的内部编码有两种,它们分别是:

  • ziplist(压缩列表):当列表中元素个数小于512(默认)个,并且列表中每个元素的值都小于64(默认)个字节。Redis会选择用ziplist来作为列表的内部实现来减少内存的使用。当然上述默认值也可以通过相关参数修改:list-max-ziplist-entried(元素个数)、list-max-ziplist-value(元素值)。
  • linkedlist(链表):当列表类型无法满足ziplist条件时,Redis会选择用linkedlist作为列表的内部实现。

下面我们通过相关命令来验证上述所说。

1.当元素个数较少并且没有大元素时,内部编码为ziplist。
img
我们看当我们在列表中插入少量元素,并且没有大元素时,返回的内部编码并不是ziplist而是quicklist。这又是什么编码呢。简单来说,quicklist编码是Redis3.2版本之后(包括当前版本)提供了一种新的内部编码。它和ziplist和linkedlist编码相比它结合了这两种编码的优势,具体的区别以后的文章中在做详细介绍。由于我电脑安装的Redis的版本是4.0.9,在3.2版本之后所以,上述代码执行后的内部编码为quicklist。


2.当元素个数超过512个元素时,内部编码将变为linkedlist。以下代码都是本人在Redis4.0.9中的测试,所以上述的验证本人没有验证成功。

import redis

r = redis.Redis(host='127.0.0.1', port=6379)

print('Key为【listkey】的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))

for i in range(1,512):
    r.rpush('listkey', i)

print('Key为【listkey的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
Key为【listkey】的字节编码为【quicklist】
Key为【listkey的字节编码为【quicklist】

3.当列表中某个元素超过64个字节时,内部编码也会变成linkedlist。以下代码也是本人在Redis4.0.9中的测试,所以上述的验证本人也没有验证成功。

import redis

r = redis.Redis(host='127.0.0.1', port=6379)

print('Key为【listkey】的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))

value = ''

for i in range(1,512):
    value += str(i)

r.rpush('listkey', i)

print('Key为【listkey的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
Key为【listkey】的字节编码为【quicklist】
Key为【listkey的字节编码为【quicklist】

上述内容就是Redis列表类型的相关知识,如有不正确的地方,欢迎指出,在下一篇中,我将分享Redis列表类型的使用场景。

原文地址:http://jilinwula.com/article/...


吉林乌拉
456 声望31 粉丝

« 上一篇
Redis哈希类型
下一篇 »
Redis集合类型