什么?Redis的List类型不会用,看我这个小白教程包你满意

  • j3_liuliang
  • Redis常用API即应用场景系列(List),如果觉得有用可以关注博主,不定时更新哦!

一、列表(List)

list命令需要知道的是它大致分两个类别L(left)R(right),顾名思义就是针对list的左边操作命令和右边操作命令从而也可以知道Redis的List数据类型其实是和队列很像的,是不是;

比如队列的先进先出对应List的命令就是先lpush再rpop后进后出就是先lpush再lpop当然命令顺序可以颠倒,这要看以那个方向为准了。

下面我以左边为准,简单的画一个List的列表操作

在这里插入图片描述

1)先从左边(lpush)开始向city列表中添加数据,数据会从左边添加进去,进而beijing会被一步步的向右边挤压;

2)接着开始从左边遍历(lrange)数据 0 到 -1 是遍历所有;

3)可以看出左边最后一个添加的guabgzhou会被第一个遍历出来,第一个添加的beijing会被最后一个遍历出来**(是不是和栈操作一样,先进后出,后进先出)**;

  • 先lpush再lpop = 栈(先进后出,后进先出)
  • 先lpush再rpop = 队列(先进先出,后进后出)

1.1 LPUSH(lpush)

将一个或多个值插入到列表头部

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

**注意:**在Redis 2.4版本以前的 LPUSH 命令,都只接受单个 value 值。

语法

127.0.0.1:6379> LPUSH KEY_NAME VALUE1.. VALUEN

可以版本:>= 1.0.0

返回值:执行 LPUSH 命令后,列表的长度。

案例

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> lpush city beijing		#从左边开始添加数据,添加一个
(integer) 1
127.0.0.1:6379> lpush city shanghai shenzhen guangzhou	#从左边开始添加数据,添加多个
(integer) 4
127.0.0.1:6379> lrange city 0 -1	#从左边开始,遍历所有数据
1) "guangzhou"
2) "shenzhen"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> 

1.2 LPOP(lpop)

移出并获取列表的第一个元素

Redis Lpop 命令用于移除并返回列表的第一个元素。

语法

127.0.0.1:6379> LLEN KEY_NAME 

可以版本:>= 1.0.0

返回值:列表的第一个元素。 当列表 key 不存在时,返回 nil 。

案例

127.0.0.1:6379> lrange city 0 -1		#遍历列表
1) "guangzhou"
2) "shenzhen"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> lpop city				#从左边移除一个元素
"guangzhou"
127.0.0.1:6379> lrange city 0 -1		#遍历列表
1) "shenzhen"
2) "shanghai"
3) "beijing"
127.0.0.1:6379> exists names			#判断key是否存在
(integer) 0
127.0.0.1:6379> lpop names				#移除不存在列表中的值,输出nil
(nil)
127.0.0.1:6379> 

1.3 LPUSHX(lpushx)

将一个或多个值插入到已存在的列表头部

Redis Lpushx 将一个或多个值插入到已存在的列表头部,列表不存在时操作无效。

语法

127.0.0.1:6379> LPUSHX KEY_NAME VALUE1.. VALUEN

可以版本:>= 2.2.0

返回值:LPUSHX 命令执行之后,列表的长度。

案例

127.0.0.1:6379> exists city					#判断city是否存在
(integer) 1
127.0.0.1:6379> lpushx city nanchang		#给存在的list列表添加值
(integer) 4									#成功
127.0.0.1:6379> exists names				#判断names是否存在
(integer) 0
127.0.0.1:6379> lpushx names j3_liuliang	#给不存在的list列表存在值
(integer) 0									#失败
127.0.0.1:6379> lrange city 0 -1			#遍历存在的列表(city)
1) "nanchang"‘
2) "shenzhen"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> 

1.4 LRANGE(lrange)

获取列表指定范围内的元素(闭区间

Redis Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

语法

127.0.0.1:6379> LRANGE KEY_NAME START END

可以版本:>= 1.0.0

返回值:一个列表,包含指定区间内的元素。

案例

127.0.0.1:6379> exists city			#该列表存在
(integer) 1
127.0.0.1:6379> lrange city 0 0		#遍历一个数据出来,闭区间
1) "nanchang"
127.0.0.1:6379> lrange city 0 1		#遍历两个数据出来,闭区间
1) "nanchang"
2) "shenzhen"
127.0.0.1:6379> lrange city 1 2		#遍历三个数据出来,闭区间
1) "shenzhen"
2) "shanghai"
127.0.0.1:6379> lrange city -2 -1	#遍历倒数第二和第一的数据,闭区间
1) "shanghai"
2) "beijing"
127.0.0.1:6379> lrange city 0 -1	#遍历第一个到最后一个数据,就是遍历全部数据
1) "nanchang"
2) "shenzhen"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> 

1.5 LINDEX(lindex)

通过索引获取列表中的元素

Redis Lindex 命令用于通过索引获取列表中的元素。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

语法

127.0.0.1:6379> LINDEX KEY_NAME INDEX_POSITION 

可以版本:>= 1.0.0

返回值:列表中下标为指定索引值的元素。 如果指定索引值不在列表的区间范围内,返回 nil 。

案例

127.0.0.1:6379> exists city			#判断列表是否存在
(integer) 1
127.0.0.1:6379> lindex city 2		#获取下标是 2 的数据,就是左边(lindex)数第三个数据
"shanghai"
127.0.0.1:6379> lindex city -1		#获取最后一个下标的数据
"beijing"
127.0.0.1:6379> lindex city 20		#获取不存在的下标数据
(nil)
127.0.0.1:6379> 

1.6 LREM(lrem)

移除列表元素

Redis Lrem 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。

COUNT 的值可以是以下几种:

  • count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
  • count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
  • count = 0 : 移除表中所有与 VALUE 相等的值。
    

语法

127.0.0.1:6379> LREM KEY_NAME COUNT VALUE

可以版本:>= 1.0.0

返回值:被移除元素的数量。 列表不存在时返回 0 。

案例

127.0.0.1:6379> lrange city 0 -1		#当前list中的数据
1) "nanchang"
2) "shenzhen"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> lrem city 1 beijing		#从表头开始移除元素
(integer) 1
127.0.0.1:6379> lrem city -1 shenzhen	#从表尾开始移除元素
(integer) 1
127.0.0.1:6379> lrem city -1 shenzhengggg	#移除没有的元素
(integer) 0
127.0.0.1:6379> lrange city 0 -1		#遍历列表
1) "nanchang"
2) "shanghai"
127.0.0.1:6379> 

1.7 LLEN(llen)

获取列表长度

Redis Llen 命令用于返回列表的长度。 如果列表 key 不存在,则 key 被解释为一个空列表,返回 0 。 如果 key 不是列表类型,返回一个错误。

语法

127.0.0.1:6379> LLEN KEY_NAME 

可以版本:>= 1.0.0

返回值:列表的长度。

案例

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> lpush city beijing shanghai shenzhen hangzhou guangzhou	#向列表中添加数据
(integer) 5
127.0.0.1:6379> llen city			#返回列表长度
(integer) 5
127.0.0.1:6379> exists names		#判断key是否存在
(integer) 0
127.0.0.1:6379> llen names			#返回不存在key的长度
(integer) 0
127.0.0.1:6379> 

1.8 LTRIM(ltrim)

对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

Redis Ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

语法

127.0.0.1:6379> LTRIM KEY_NAME START STOP

可以版本:>= 1.0.0

返回值:命令执行成功时,返回 ok 。

案例

127.0.0.1:6379> lpush names j3_liuliang xiaohong xiaoma xiaoli xiaohua xiaowang	#添加数据
(integer) 6
127.0.0.1:6379> ltrim names 0 -2		#保留第一个到倒数第二个数之间的值
OK
127.0.0.1:6379> lrange names 0 -1		#遍历
1) "xiaowang"
2) "xiaohua"
3) "xiaoli"
4) "xiaoma"
5) "xiaohong"
127.0.0.1:6379> ltrim names 30 -2		#保留从 30 到 倒数第二个数之间的数
OK
127.0.0.1:6379> lrange names 0 -1		#为空了
(empty list or set)
127.0.0.1:6379> lpush names j3_liuliang xiaohong xiaoma xiaoli xiaohua xiaowang #添加数据
(integer) 6
127.0.0.1:6379> ltrim names 0 -20		#保留从第一个,到 倒数第二十个之间的数
OK
127.0.0.1:6379> lrange names 0 -1		#为空了
(empty list or set)
127.0.0.1:6379> 

1.9 LINSERT(linsert)

在列表的元素前或者后插入元素

Redis Linsert 命令用于在列表的元素前或者后插入元素。 当指定元素不存在于列表中时,不执行任何操作。 当列表不存在时,被视为空列表,不执行任何操作。 如果 key 不是列表类型,返回一个错误。

语法

LINSERT KEY_NAME BEFORE EXISTING_VALUE NEW_VALUE 

可以版本:>= 1.0.0

返回值:如果命令执行成功,返回插入操作完成之后,列表的长度。 如果没有找到指定元素 ,返回 -1 。 如果 key 不存在或为空列表,返回 0 。

案例

127.0.0.1:6379> lrange city 0 -1			#遍历列表
1) "guangzhou"
2) "hangzhou"
3) "shenzhen"
4) "shanghai"
5) "beijing"
127.0.0.1:6379> linsert city before beijing tianjing	#在beijing的前面插入tianjing
(integer) 6
127.0.0.1:6379> lrange city 0 -1			#遍历列表,查看效果
1) "guangzhou"
2) "hangzhou"
3) "shenzhen"
4) "shanghai"
5) "tianjing"
6) "beijing"
127.0.0.1:6379> linsert city after guangzhou dongwan		#在guangzhou的后面插入dongwan
(integer) 7
127.0.0.1:6379> lrange city 0 -1			#遍历列表,查看效果
1) "guangzhou"
2) "dongwan"
3) "hangzhou"
4) "shenzhen"
5) "shanghai"
6) "tianjing"
7) "beijing"
127.0.0.1:6379> 

1.10 LSET(lset)

通过索引设置列表元素的值

Redis Lset 通过索引来设置元素的值。

当索引参数超出范围,或对一个空列表进行 LSET 时,返回一个错误。

语法

127.0.0.1:6379> LSET KEY_NAME INDEX VALUE

可以版本:>= 1.0.0

返回值:操作成功返回 ok ,否则返回错误信息。

案例

127.0.0.1:6379> lrange city 0 -1			#当前列表数据
1) "guangzhou"
2) "dongwan"
3) "hangzhou"
4) "shenzhen"
5) "shanghai"
6) "tianjing"
7) "beijing"
127.0.0.1:6379> lset city 0 guangzhou1111	#将下标为 0 的数据 改为 guangzhou1111
OK
127.0.0.1:6379> lrange city 0 -1			#遍历列表查看效果
1) "guangzhou1111"
2) "dongwan"
3) "hangzhou"
4) "shenzhen"
5) "shanghai"
6) "tianjing"
7) "beijing"
127.0.0.1:6379> lset city 3 shenzhen0000000	#将下标为 3 的数据改为 shenzhen0000000
OK
127.0.0.1:6379> lrange city 0 -1			#遍历列表查看效果
1) "guangzhou1111"
2) "dongwan"
3) "hangzhou"
4) "shenzhen0000000"
5) "shanghai"
6) "tianjing"
7) "beijing"
127.0.0.1:6379> lset city 30 shenzhen0000000	#给不存在的下标,设置数据
(error) ERR index out of range					#出错,下标越界
127.0.0.1:6379> lrange city 0 -1				#列表数据,没有变化
1) "guangzhou1111"
2) "dongwan"
3) "hangzhou"
4) "shenzhen0000000"
5) "shanghai"
6) "tianjing"
7) "beijing"
127.0.0.1:6379> 

1.11 RPUSH(rpush)

在列表中添加一个或多个值

Redis Rpush 命令用于将一个或多个值插入到列表的尾部(最右边)。

如果列表不存在,一个空列表会被创建并执行 RPUSH 操作。 当列表存在但不是列表类型时,返回一个错误。

**注意:**在 Redis 2.4 版本以前的 RPUSH 命令,都只接受单个 value 值。

语法

127.0.0.1:6379> RPUSH KEY_NAME VALUE1..VALUEN

可以版本:>= 1.0.0

返回值:执行 RPUSH 操作后,列表的长度。

案例

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> rpush city beijing shanghai guangzhou shenzhen	#从左边开始添加数据,多个
(integer) 4
127.0.0.1:6379> rpush city hangzhou	#从左边开始添加数据,单个
(integer) 5
127.0.0.1:6379> lrange city 0 -1	#从右边开始遍历数据
1) "beijing"
2) "shanghai"
3) "guangzhou"
4) "shenzhen"
5) "hangzhou"
127.0.0.1:6379> 

1.12 RPOP(rpop)

移除并获取列表最后一个元素

Redis Rpop 命令用于移除并返回列表的最后一个元素。

语法

127.0.0.1:6379> RPOP KEY_NAME 

可以版本:>= 1.0.0

返回值:列表的最后一个元素。 当列表不存在时,返回 nil 。

案例

127.0.0.1:6379> lrange city 0 -1	#当前列表数据
1) "beijing"
2) "shanghai"
3) "guangzhou"
4) "shenzhen"
5) "hangzhou"
127.0.0.1:6379> rpop city			#从右边移除数据(一个)
"hangzhou"
127.0.0.1:6379> exists names		#判断key是否存在
(integer) 0
127.0.0.1:6379> rpop names			#移除不存在key的值,返回nil
(nil)
127.0.0.1:6379> 

1.13 RPUSHX(rpushx)

为已存在的列表添加值

Redis Rpushx 命令用于将一个或多个值插入到已存在的列表尾部(最右边)。如果列表不存在,操作无效。

语法

127.0.0.1:6379> RPUSHX KEY_NAME VALUE1..VALUEN

可以版本:>= 2.2.0

返回值:执行 Rpushx 操作后,列表的长度。

案例

127.0.0.1:6379> lrange city 0 -1		#当前列表中数据
1) "beijing"
2) "shanghai"
3) "guangzhou"
4) "shenzhen"
127.0.0.1:6379> rpushx city tianjin		#向存在的列表添加数据(从右边开始)
(integer) 5
127.0.0.1:6379> lrange city 0 -1		#当前列表数据
1) "beijing"
2) "shanghai"
3) "guangzhou"
4) "shenzhen"
5) "tianjin"
127.0.0.1:6379> exists names			#判断key是否存在
(integer) 0
127.0.0.1:6379> rpushx names j3_liuliang	#给不存在的key添加数据
(integer) 0									#失败
127.0.0.1:6379> exists names				#没有任何变化,不会创建数据
(integer) 0
127.0.0.1:6379> 

1.14 RPOPLPUSH(rpoplpush)

移除列表的最后一个元素,并将该元素添加到另一个列表并返回

Redis Rpoplpush 命令用于移除列表的最后一个元素,并将该元素添加到另一个列表并返回。

语法

127.0.0.1:6379> RPOPLPUSH SOURCE_KEY_NAME DESTINATION_KEY_NAME

可以版本:>= 1.0.0

返回值:被弹出的元素。

案例

127.0.0.1:6379> lrange city 0 -1		#city列表数据
1) "beijing"
2) "shanghai"
3) "guangzhou"
4) "shenzhen"
5) "tianjin"
127.0.0.1:6379> lrange names 0 -1		#names列表数据
1) "j3_liuliang"
127.0.0.1:6379> rpoplpush city names	#将city中最后一个数据弹出添加到names中
"tianjin"
127.0.0.1:6379> lrange city 0 -1		#查看全部数据
1) "beijing"
2) "shanghai"
3) "guangzhou"
4) "shenzhen"
127.0.0.1:6379> lrange names 0 -1		#查看全部数据
1) "tianjin"
2) "j3_liuliang"
127.0.0.1:6379> 

1.15 BLPOP(blpop)

移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。类比阻塞队列

Redis Blpop 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

语法

127.0.0.1:6379> BLPOP LIST1 LIST2 .. LISTN TIMEOUT

可以版本:>= 2.0.0

返回值:如果列表为空,返回一个 nil 。 否则,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。

案例

127.0.0.1:6379> lrange names 0 -1		#当前列表所有数据
1) "tianjin"
2) "j3_liuliang"
127.0.0.1:6379> blpop names 5			#弹出一个数据从该列表中,如果该列表中没有数据,等待 5 秒,如果该列表没有被其他线程添加数据的化,											就会返回nil,如果有其他的数据添加进来就会立即返回该数据
1) "names"
2) "tianjin"
127.0.0.1:6379> lrange names 0 -1		#当前列表所有数据
1) "j3_liuliang"
127.0.0.1:6379> blpop names 5			#弹出一个数据从该列表中,如果该列表中没有数据,等待 5 秒,如果该列表没有被其他线程添加数据的化,											就会返回nil,如果有其他的数据添加进来就会立即返回该数据
1) "names"		
2) "j3_liuliang"
127.0.0.1:6379> blpop names 50			#上面可知,names已经空了,所有在弹出数据时,会等待 50 秒,如果names中没有其他数据添加进来,过时											直接返回nil否者直接返回添加的数据
1) "names"
2) "xiaowang"							#这是我开的另一个客户端向names中添加数据的,所以这个客户端会立马被感知弹出数据,用户16.79秒
(16.79s)
127.0.0.1:6379> 

1.16 BRPOP(brpop)

移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。类比阻塞队列

Redis Brpop 命令移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

语法

127.0.0.1:6379> BRPOP LIST1 LIST2 .. LISTN TIMEOUT 

可以版本:>= 2.0.0

返回值:假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。

案例

# 和blpop的操作一样,只是一个方向问题,案例可以参考blpop命令

1.17 BRPOPLPUSH(brpoplpush)

从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

Redis Brpoplpush 命令从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

语法

127.0.0.1:6379> BRPOPLPUSH LIST1 ANOTHER_LIST TIMEOUT 

可以版本:>= 2.0.0

返回值:假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。

案例

# brpoplpush 和 rpoplpush的效果一样,不同的就是加了一个等待时间,如果list中没有数据,规定时间内没有添加的话,会返回nil
127.0.0.1:6379> keys *						
1) "name"
2) "city"
127.0.0.1:6379> lrange name 0 -1			#name列表中的数据
1) "xiaowang"
127.0.0.1:6379> brpoplpush name city 10		#当name中有数据时,brpoplpush 和 rpoplpush操作效果一样
"xiaowang"
127.0.0.1:6379> brpoplpush name city 100	#当 name 中数据为空时 brpoplpush 会先阻塞100 秒等待name中添加数据,才会执行会须操作,如											果100秒之后还是没有数据,那么返回nil
"xiaoliu"
(26.60s)	#等待26秒执行成功!
127.0.0.1:6379> 

二、应用场景

2.1 消息队列

如下图所示,Redis的lpush + brpop命令组合即可实现阻塞队列,生产者客户端使用lpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的争抢列表尾部的元素,多个客户端保证了消费的负载均衡和高可用;

在这里插入图片描述

2.2 栈

可以通过(lpush lpop左边进左边出,或rpush rpop 右边进右边出),实现先进后出原则

2.3 最新列表

list类型的lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表,如朋友圈的点赞列表、评论列表。

但是,并不是所有的最新列表都能用list类型实现,因为对于频繁更新的列表,list类型的分页可能导致列表元素重复或漏掉,举个例子,当前列表里由表头到表尾依次有(E,D,C,B,A)五个元素,每页获取3个元素,用户第一次获取到(E,D,C)三个元素,然后表头新增了一个元素F,列表变成了(F,E,D,C,B,A),此时用户取第二页拿到(C,B,A),元素C重复了。只有不需要分页(比如每次都只取列表的前5个元素)或者更新频率低(比如每天凌晨更新一次)的列表才适合用list类型实现。对于需要分页并且会频繁更新的列表,需用使用有序集合sorted set类型实现。另外,需要通过时间范围查找的最新列表,list类型也实现不了,也需要通过有序集合sorted set类型实现,如以成交时间范围作为条件来查询的订单列表。之后在介绍有序集合sorted set类型的应用场景时会详细介绍sorted set类型如何实现最新列表。

2.4 排行榜

list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中,如京东每日的手机销量排行、学校每次月考学生的成绩排名、斗鱼年终盛典主播排名等;

但是,并不是所有的排行榜都能用list类型实现,只有定时计算的排行榜才适合使用list类型存储,与定时计算的排行榜相对应的是实时计算的排行榜,list类型不能支持实时计算的排行榜,之后在介绍有序集合sorted set的应用场景时会简单说一下。

结束语

  • 本文结合Redis中文网和博主的实践案例所写,下期写Hash类型
  • 由于博主才疏学浅,难免会有纰漏,假如你发现了错误或偏见的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40399646/article/details/108912877