(4)Redis 数据结构(List的操作)

第四节:Redis 数据结构之List 类型  
存储list:
ArrayList使用数组方式
LinkedList使用双向链接方式
 
双向链接表中增加数据
双向链接表中删除数据
 
存储list常用命令
两端添加
两端弹出
扩展命令
 
下面是操作命令的例子:
 
lpush 方式从左边开始添加
127.0.0.1:6379> lpush list1 a b c d
(integer) 4
127.0.0.1:6379> lpush list1 1 2 3 4
(integer) 8
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "d"
6) "c"
7) "b"
8) "a"
127.0.0.1:6379> lrange list1 0 4
1) "4"
2) "3"
3) "2"
4) "1"
5) "d"

lrange索引下标特点:从左到右为0到n-1

lrange 0 -1  命令可以从左到右获取列表的所有元素

 

rpush 从右端开始添加(一般人比较习惯这种方式)
127.0.0.1:6379> rpush list2 a b c d
(integer) 4
127.0.0.1:6379> rpush list2 1 2 3 4
(integer) 8
127.0.0.1:6379> lrange list2 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "1"
6) "2"
7) "3"
8) "4"

 

rpop 右侧弹出集合元素
127.0.0.1:6379> lrange list2 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "1"
6) "2"
7) "3"
8) "4"
127.0.0.1:6379> rpop list2
"4"
127.0.0.1:6379> lrange list2 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "1"
6) "2"
7) "3"

 

lpop 左侧弹出集合元素
127.0.0.1:6379> lrange list2 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "1"
6) "2"
7) "3"
127.0.0.1:6379> lpop list2
"a"
127.0.0.1:6379> lrange list2 0 -1
1) "b"
2) "c"
3) "d"
4) "1"
5) "2"
6) "3"

 

自评:关于lpush、rpush、lpop、rpop的使用问题

比如rpush按顺序添加a b c d四个元素,添加完之后元素存放位置如下:

a b c d

这时候,如果:

lpop:  返回a,先进先出  

rpop:  返回d,先进后出

项目中有个权益券码的保存和使用是这样的:

1.存在toolList:tool1, tool2, tool3
2.插入数据库后顺序是:tool3,tool2, tool1
2.使用rightPushAll: tool1, tool2, tool3
3.push完成之后key的值:equity:stock:equityId_001 - [tool1, tool2, tool3]
4.lpop消费1个返回:tool1

这样是先入库的后消费了。

 

 

llen查看元素个数
127.0.0.1:6379> llen list2
(integer) 6

 

lpushx 集合头部插入元素
127.0.0.1:6379> lrange list2 0 -1
1) "b"
2) "c"
3) "d"
4) "1"
5) "2"
6) "3"
127.0.0.1:6379> lpushx list2 zhangsan
(integer) 7
127.0.0.1:6379> lrange list2 0 -1
1) "zhangsan"
2) "b"
3) "c"
4) "d"
5) "1"
6) "2"
7) "3"

 

rpushx 集合尾部插入元素
127.0.0.1:6379> lrange list2 0 -1
1) "zhangsan"
2) "b"
3) "c"
4) "d"
5) "1"
6) "2"
7) "3"
127.0.0.1:6379> rpushx list2 lisi
(integer) 8
127.0.0.1:6379> lrange list2 0 -1
1) "zhangsan"
2) "b"
3) "c"
4) "d"
5) "1"
6) "2"
7) "3"
8) "lisi"

 

lpush集合头部插入多个元素
rpush集合尾部插入多个元素
127.0.0.1:6379> lrange list2 0 -1
1) "b"
2) "c"
3) "d"
4) "1"
5) "2"
6) "3"
127.0.0.1:6379> lpush list2 a1 a2
(integer) 8
127.0.0.1:6379> lrange list2 0 -1
1) "a2"
2) "a1"
3) "b"
4) "c"
5) "d"
6) "1"
7) "2"
8) "3"
127.0.0.1:6379> lrange list2 0 -1
1) "b"
2) "c"
3) "d"
4) "1"
5) "2"
6) "3"
127.0.0.1:6379> rpush list2 zhangsan lisi
(integer) 8
127.0.0.1:6379> lrange list2 0 -1
1) "b"
2) "c"
3) "d"
4) "1"
5) "2"
6) "3"
7) "zhangsan"
8) "lisi"

 

lpush和lpushx的区别:

核心区别在于:当键key不存在时,它们的行为完全不同。LPUSH总是创建一个新列表并插入元素,而LPUSHX只在列表已存在时才插入元素,否则什么也不做。

这个规则同样适用于rpush和rpushx

 

Redis List作为消息队列任务队列的经典用法:

使用RPUSH(从右端生产) + LPOP(从左端消费)组合,完美实现了先进先出(FIFO)的顺序。

#生产者(存入):使用RPUSH将券码依次从列表右侧推入。
RPUSH voucher_queue "codeA" "codeB" "codeC"            # 此时列表为:["codeA", "codeB", "codeC"]

# 消费者(取出):使用LPOP从列表左侧弹出。
"codeA"                                                # 第一次LPOP取出"codeA",列表变为["codeB", "codeC"]

 

但是生产环境必须解决的两个问题:

1.并发消费导致同一券码被多次领取(竞争条件)

  • 场景:两个消费者(如两台服务器上的程序)同时执行LPOP

  • 风险:虽然LPOP本身是原子操作(不会取出同一个元素两次),但如果在“取出券码”和“标记已使用”之间发生了网络延迟或程序崩溃,这个券码可能已经从队列移除但未被成功核销,导致券码丢失

2.消费者崩溃导致正在处理的券码永久丢失

  • 场景:消费者用LPOP取出了券码A,但在核销A的过程中(比如调用第三方接口)服务器突然宕机。

  • 风险:A已经从队列中永久移除,但核销未完成,这张券永远无法被再次消费,造成资损。

 

生产级解决方案:使用 RPOPLPUSH 或 BRPOPLPUSH

 

lrem 从指定方向删除指定个数的指定元素
127.0.0.1:6379> lpush list4 1 3 2 3 2 1 2 1 3
(integer) 9
127.0.0.1:6379> lrange list4 0 -1
1) "3"
2) "1"
3) "2"
4) "1"
5) "2"
6) "3"
7) "2"
8) "3"
9) "1"
从左边开始删除2个1
127.0.0.1:6379> lrem list4 2 1
(integer) 2
127.0.0.1:6379> lrange list4 0 -1
1) "3"
2) "2"
3) "2"
4) "3"
5) "2"
6) "3"
7) "1"
从右边开始删除2个3
127.0.0.1:6379> lrem list4 -2 3
(integer) 2
127.0.0.1:6379> lrange list4 0 -1
1) "3"
2) "2"
3) "2"
4) "2"
5) "1"
删除所有2
127.0.0.1:6379> lrem list4 0 2
(integer) 3
127.0.0.1:6379> lrange list4 0 -1
1) "3"
2) "1"

 

lset 设置集合指定索引的值
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "d"
6) "c"
7) "b"
8) "a"
127.0.0.1:6379> lset list1 3 xxxx
OK
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "xxxx"
5) "d"
6) "c"
7) "b"
8) "a"

 

linsert 在集合里插入指定元素
在xxxx元素之前插入aa
127.0.0.1:6379> linsert list1 before xxxx aa
(integer) 9
127.0.0.1:6379> lrange list1 0 -1
1) "4"
2) "3"
3) "2"
4) "aa"
5) "xxxx"
6) "d"
7) "c"
8) "b"
9) "a"
在xxxx元素之后插入bb
127.0.0.1:6379> linsert list1 after xxxx bb
(integer) 10
127.0.0.1:6379> lrange list1 0 -1
 1) "4"
 2) "3"
 3) "2"
 4) "aa"
 5) "xxxx"
 6) "bb"
 7) "d"
 8) "c"
 9) "b"
10) "a"

 

rpoplpush 把A集合尾部元素弹出并插入到B集合头部
127.0.0.1:6379> rpush list5 a b c
(integer) 3
127.0.0.1:6379> rpush list6 1 2 3
(integer) 3
127.0.0.1:6379> rpoplpush list5 list6
"c"
127.0.0.1:6379> lrange list5 0 -1
1) "a"
2) "b"
127.0.0.1:6379> lrange list6 0 -1
1) "c"
2) "1"
3) "2"
4) "3"

 

posted on 2018-04-01 00:05  有点懒惰的大青年  阅读(207)  评论(0)    收藏  举报