Redis 2 List Set
uwupu 啦啦啦啦啦

List

Redis List就是双端链表;

Redis List 实现字符串的链表,可以用来:

  • 实现栈和队列;
  • 为后台系统提供队列管理。比如应用将任务push到List队列,工作线程使用pop操作将任务取出并执行。

一些简单的使用

实现一个队列(先进先出)

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> lpush work:queue 1
(integer) 1
127.0.0.1:6379> lpush work:queue 2
(integer) 2
127.0.0.1:6379> lpush work:queue 3
(integer) 3
127.0.0.1:6379> rpop work:queue
"1"
127.0.0.1:6379> rpop work:queue
"2"
127.0.0.1:6379> rpop work:queue
"3"

lpush,左边推入,rpop,右边弹出。

实现一个栈(先进,后出)

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> lpush work:queue 1
(integer) 1
127.0.0.1:6379> lpush work:queue 2
(integer) 2
127.0.0.1:6379> lpush work:queue 3
(integer) 3
127.0.0.1:6379> lpop work:queue
"3"
127.0.0.1:6379> lpop work:queue
"2"
127.0.0.1:6379> lpop work:queue
"1"

lpush,左边推入,lpop,左边弹出。

获得链表的长度

1
2
3
4
5
6
7
8
127.0.0.1:6379> lpush q2 1
(integer) 1
127.0.0.1:6379> lpush q2 2
(integer) 2
127.0.0.1:6379> lpush q2 3
(integer) 3
127.0.0.1:6379> llen q2
(integer) 3

llen,获取链表长度。

原子性地从一个列表弹出并放进另一个列表

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> lpush q-todo 101
(integer) 1
127.0.0.1:6379> lpush q-todo 102
(integer) 2
127.0.0.1:6379> lmove q-todo q-progress LEFT LEFT
"102"
127.0.0.1:6379> lrange q-todo 0 -1
1) "101"
127.0.0.1:6379> lrange q-progress 0 -1
1) "102"

先向队列q-todo里面添加101,102;

然后使用lmove,将q-todo里的左边取出移动到q-progress的左边。

即:从一个列表弹出数据并放进另一个列表。

这是一个原子性地不可分割的操作。

LEFT指定左边,RIGHT指定右边

限制

最大长度为2^32-1(4_294_967_295)个元素。

命令

lpush 添加

lpush key element [element ...]

向key依次推入多个element元素;

若key为空则创建队列;若key有值且为其他类型,则返回error;

返回值为push后的队列长度。

lpushx 没有则添加

lpushx key element [element ...]

与lpush类似,不同的是:

  • 仅当key存在时,才会执行;
  • 若key不存在则不会执行
  • 返回值为push后的长度

lrange 查询

lrange key start stop

  • 返回指定范围的key队列内的元素,start从0开始,-1表示最后一个元素;

  • 若超出范围不会发生错误,若start超出列表长度,则返回一个空列表;若stop大于列表长度,Redis会视为列表的最后一个元素。

  • 获取的值是否包含stop所在位置,依据不同编程语言进行处理。

lrem 删除返回数量

lrem key count element

  • 删除key队列里指定数量的element

  • count值决定删除的数量和删除的起点

    • count > 0 ,从起点开始寻找并删除队列里与element相同的值,删除数量为count;
    • count < 0 ,从队列尾部删除值;
    • count = 0 ,删除所有的与element相同的值。
  • 返回值为删除的数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
127.0.0.1:6379> lpush c 1 2 3 4 2 3 2 1 4 2 3 4 2 5 2
(integer) 15
127.0.0.1:6379> lrem c 3 2
(integer) 3
127.0.0.1:6379> lrange c 0 -1
1) "5"
2) "4"
3) "3"
4) "4"
5) "1"
6) "2"
7) "3"
8) "2"
9) "4"
10) "3"
11) "2"
12) "1"

lset 设置

lset key index element

设置key的index位置的值为element。

ltrim 截取

ltrim key start stop

使队列仅包含指定范围的值。

超出范围不会报错;若start大于length或start大于stop,会变成空队列(即删除这个队列);若stop大于length,则视为最后一个元素。

1
2
3
4
5
6
7
8
127.0.0.1:6379> lpush q2 a b c d e  # q2中有 e d c b a
(integer) 5
127.0.0.1:6379> ltrim q2 1 3 # 取出其中的1~3
OK
127.0.0.1:6379> lrange q2 0 -1 # 即 d c b
1) "d"
2) "c"
3) "b"

lpop 删除并返回值

lpop key [count]

删除指定数量的元素并返回指定数量的元素。

1
2
3
4
127.0.0.1:6379> lpop c 3
1) "5"
2) "4"
3) "3"

lpos 寻找

lpos key value [RANK level] [COUNT num-matches]

说明

  • 检索指定值的位置;

  • 在key数列中寻找value的位置,返回位置的索引;

参数

  • RANK,数列中可能有多个与value相同的值,RANK指定返回第几个value的值;

  • COUNT,指定要返回的数量。

  • RANK可以和COUNT一起使用,将返回从第level个开始,COUNT数量个值。

返回值

  • 若成功匹配,返回一个数组;

  • 若未使用COUNT且没有匹配到value,则返回nil;

  • 若使用COUNT没有匹配到value,返回空数列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
127.0.0.1:6379> lrange c 0 -1
1) "4"
2) "1"
3) "2"
4) "3"
5) "2"
6) "4"
7) "3"
8) "2"
9) "1"
127.0.0.1:6379> lpos c 2 RANK -2 #获取c中的“2”,从尾部到头部第二个
(integer) 4
127.0.0.1:6379> lpos c 2 COUNT 3 #获取c中的"2",获取3个。
1) (integer) 2
2) (integer) 4
3) (integer) 7
127.0.0.1:6379> lpos c 2 count 3 rank -1 #从尾部的第一个开始,获取三个数量的位置
1) (integer) 7
2) (integer) 4
3) (integer) 2

lmove 移动到另一个队列

lmove source destination <LEFT | RIGHT> <LEFT | RIGHT>

将source的元素移动到destination中;

LEFT表示左边,RIGHT表示右边;

lmpop 多key弹出

lmpop numkeys key [key ...] <LEFT |RIGHT> [COUNT count]

依次从多个key对应的队列中弹出数据,可以指定数量和方向;

numkeys:输入的key的数量;

举例:

1
2
3
4
lmpop 2 q1 q2 LEFT COUNT 3  
# 2为key的数量,这里有两个key:q1 q2
# LEFT为方向,也可以是RIGHT
# 3为数量,这里指一次弹出三个值。

运行过程:

  • 首先判断q1中是否有元素,若有则弹出;
    • 若数量不足三个,则弹出剩余的值;
  • 若q1为空,则从q2中弹出;
    • 若q1的数量不足三个,不用q2中的补足数量;
    • 若数量不足三个,弹出剩余的值。
  • 若都为空,则返回nil;

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
127.0.0.1:6379> lpush q1 1 2 3 4 5   #首先在q1中输入 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lpush q2 a b c d e # 在q2中输入 a b c d e
(integer) 5

# 方向RIGHT 数量4 key数量为2 两个key:q1 q2
127.0.0.1:6379> lmpop 2 q1 q2 RIGHT COUNT 4
1) "q1"
2) 1) "1"
2) "2"
3) "3"
4) "4"
# 弹出q1中右边开始的4个值
# 方向RIGHT,数量4 key数量2 两个key: q1 q2
127.0.0.1:6379> lmpop 2 q1 q2 RIGHT COUNT 4
1) "q1"
2) 1) "5"
# q1中只剩下5 ,则弹出
# 方向RIGHT,数量4 key数量2 两个key: q1 q2
127.0.0.1:6379> lmpop 2 q1 q2 RIGHT COUNT 4
1) "q2"
2) 1) "a"
2) "b"
3) "c"
4) "d"
# 弹出q2中右边开始的4个值
127.0.0.1:6379> lmpop 2 q1 q2 RIGHT COUNT 4
1) "q2"
2) 1) "e"
# q2中只剩下一个“e”,所以弹出
127.0.0.1:6379> lmpop 2 q1 q2 RIGHT COUNT 4
(nil)
# 若两个队列都为空,则返回nil

llen 长度

llen key

获取队列长度。

linsert 插入到已知值附近

linsert key <BEFORE | AFTER> pivot element

插入element到key对应队列的值为pivot的前面或后面。

pivot:参考位置的值;

返回值:

  • 若成功,返回队列的长度;
  • 若pivot没有被找到,返回-1;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> lpush q1 1 2 3 4 5  # q1中有5 4 3 2 1
(integer) 5
127.0.0.1:6379> linsert q1 BEFORE 3 q # 在3的前面插入q
(integer) 6
127.0.0.1:6379> linsert q1 after 4 w # 在4的后面插入w
(integer) 7
127.0.0.1:6379> lrange q1 0 -1 # 获取所有值
1) "5"
2) "4"
3) "w" # w在4的后面
4) "q" # q在3的前面
5) "3"
6) "2"
7) "1"

lindex 依据索引获得值

lindex key index

返回索引为index的位置的值;

1
2
3
4
127.0.0.1:6379> lpush q1 1 2 3 4 5  # q1为 5 4 3 2 1 
(integer) 5
127.0.0.1:6379> lindex q1 3 # 返回索引为4的值
"2"

R系列 从右边开始操作

RPOP key [count]:从队列右边弹出指定数量的数据,空则返回nil;

RPUSH key element [element ...]:从队列右边添加数据,返回操作后队列的长度,若key不存在则创建队列;

RPUSHX key element [element ...]:类似于RPUSH,若key不存在则不执行任何操作。

blmove 阻塞的元素移动

blmove source destination <LEFT | RIGHT> <LEFT | RIGHT> timeout

lmove的带阻塞功能的版本;

可以将队列中的数据从一个队列A移动到另一个队列B;

阻塞功能:若队列A为空,Redis会对连接进行阻塞,直到另一个客户端为队列A加入内容;

timeout最长等待时间,为零可以无限期阻塞;

返回值为一组字符串;若timeout到达时,返回null;

blmpop 阻塞的多数据弹出

blmpop timeout numkeys key [key ...] <LEFT | RIGHT> [COUNT count]

超时返回nil;

blpop 阻塞的数据弹出

BLPOP key [key ...] timeout

相对于lpop,可以有多个key,Redis将依照key依次检索,直到有key的队列不为空,弹出并返回;

timeout可以为0,表示无限期等待。

brpop 阻塞的数据弹出,从右边开始

BRPOP key [key ...] timeout

Set

Redis Set通过哈希表实现;添加、删除、查找的复杂度都是O(1);

Redis Set是String的无序集合,集合成员是惟一的,不可重复的;

可以用来

  • 标签,为用户添加标签;
  • 点赞、踩、收藏的数量,用set实现;
  • 集合的操作:并集、交集和差集。

例子

  • 存储A和B喜欢的书的id

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> sadd user:A:favorites 1  # 用户A喜欢id为1的书籍
    (integer) 1
    127.0.0.1:6379> sadd user:A:favorites 2 # 用户A喜欢id为2的书籍
    (integer) 1
    127.0.0.1:6379> sadd user:A:favorites 3 # 用户A喜欢id为3的书籍
    (integer) 1
    127.0.0.1:6379> sadd user:B:favorites 2 # 用户B喜欢id为2的书籍
    (integer) 1
  • 检查用户A是否喜欢书籍2和书籍5

    1
    2
    3
    4
    127.0.0.1:6379> sismember user:A:favorites 2  # A喜欢书2
    (integer) 1
    127.0.0.1:6379> sismember user:A:favorites 5 # A不喜欢书5
    (integer) 0
  • 用户A和用户B有共同喜欢的书

    1
    2
    127.0.0.1:6379> sinter user:A:favorites user:B:favorites 
    1) "2" # A和B都喜欢书2
  • 用户A喜欢几本书

    1
    2
    127.0.0.1:6379> scard user:A:favorites
    (integer) 3

限制

最大大小2^32-1个成员

基本命令

SADD 将新成员添加到集合中;

SREM 从集合中删除指定成员;

SISMEMBER 测试集合中是否存在某个成员;

SINTER 返回两个或多个集合共有成员集合(交集);

SCARD 返回集合大小。

完整命令

SADD 添加

SADD key member [member ...]

添加指定的成员作为集合到key中;

若成员原本就在集合中,则不添加;

若key不存在,则创建一个集合并将成员添加到集合中;

若key存在且不是一个set,则返回错误;

返回添加到集合成员的数量,不包含原本在集合的成员。

1
2
3
4
5
6
7
8
127.0.0.1:6379> sadd s1 q w e r t
(integer) 5
127.0.0.1:6379> smembers s1
1) "r"
2) "e"
3) "w"
4) "q"
5) "t"

SMOVE 移动成员

SMOVE source destination member

移动成员member从source到destination中;

这是一个原子性操作,在执行期间,对于其他客户端,这个成员将同时属于source和destination;

如果source不存在或不包含指定元素,操作将不会执行且返回0;

若指定元素已经存在于destination中,则元素仅仅从source中删除;

若source或destination不是set类型,则返回错误。

返回1表示执行成功,0表示操作未执行;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> sadd s1 q w e
(integer) 3
127.0.0.1:6379> sadd s2 z x c
(integer) 3
127.0.0.1:6379> smove s1 s2 w # 将w从s1移动到s2
(integer) 1
127.0.0.1:6379> smembers s1
1) "e"
2) "q"
127.0.0.1:6379> smembers s2
1) "x"
2) "z"
3) "w"
4) "c"

SREM 移除成员

srem key member [member ...]

从set中移除指定成员;

若指定成员不存在,则忽略;

若key不存在将返回0。

成功返回移除的数量,不包括之前本就不存在的对象。

1
2
3
4
5
6
7
8
127.0.0.1:6379> sadd s1 q w e r t
(integer) 5
127.0.0.1:6379> srem s1 w e # 从q1中移除了w和e
(integer) 2
127.0.0.1:6379> smembers s1
1) "r"
2) "q"
3) "t"

SPOP 移除并返回成员

spop key [count]

从set移除并返回一个或多个随机成员;

若不指定数量,默认弹出一个成员;

若提供数量,将移除并返回指定数量的成员;

返回值:

  • 若没有指定count,则返回删除的对象,若key不存在返回nil;
  • 若指定了count,则返回删除的对象,若key不存在返回一个空数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> smembers s1  # s1的所有对象
1) "r"
2) "q"
3) "t"
127.0.0.1:6379> spop s1 2 # 弹出s1中两个对象
1) "q"
2) "r"
127.0.0.1:6379> spop s1 2 # 弹出s1中两个对象,目前只剩下一个对象,所以弹出一个对象;
1) "t"
127.0.0.1:6379> spop s1 2 # 指定count,返回空数组
(empty array)
127.0.0.1:6379> spop s1 # 不指定count,返回nil
(nil)

SCARD 成员数量

scard key

返回集合中成员的数量

1
2
3
4
127.0.0.1:6379> sadd s1 q w e r t
(integer) 5
127.0.0.1:6379> scard s1
(integer) 5

SDIFF

sdiff key [key ...]

返回第一个set与其他指定set的差集

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> sadd s1 q w e r t
(integer) 5
127.0.0.1:6379> sadd s2 a w e d f
(integer) 5
127.0.0.1:6379> sadd s3 q z x c g
(integer) 5
127.0.0.1:6379> sdiff s1 s2 s3 # s1与s2、s3的差集
1) "r"
2) "t"

SDIFFSTORE

sdiffstore destination key [key ...]

功能类似于sdiff,不同的是,sdiffstore会将差集结果存放到destination里,返回值变为差集结果的长度;

若destination中已存在值,则覆盖

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> sadd s1 q w e r t
(integer) 5
127.0.0.1:6379> sadd s2 q w e
(integer) 3
127.0.0.1:6379> sdiffstore s3 s1 s2
(integer) 2
127.0.0.1:6379> smembers s3
1) "r"
2) "t"

SINTER

sinter key [key ...]

返回给定所有set的交集;

不存在的键被认为是空集,即结果也为空集。

1
2
3
4
5
6
7
127.0.0.1:6379> sadd s1 q w e r t
(integer) 5
127.0.0.1:6379> sadd s2 q w z x c
(integer) 5
127.0.0.1:6379> sinter s1 s2
1) "w"
2) "q"

SINTERCARD

sintercard numkeys key [key ...] [LIMIT limit]

numkeys:key的数量;

功能类似于sinter,返回多个集合交集结果集的元素数量,;

limit可以限制计算数量,若计算数量达到limit,则返回limit;

1
2
3
4
127.0.0.1:6379> sintercard 2 s1 s2
(integer) 2
127.0.0.1:6379> sintercard 2 s1 s2 limit 1
(integer) 1

SINTERSTORE

sinterstore destination key [key ...]

numskeys:key的数量;

功能类似于sinter,不同的是sinterstore将交集的结果存放到destination,返回值为长度;

若destination已存在,则进行覆盖。

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> sadd q1 q w e r t
(integer) 5
127.0.0.1:6379> sadd q2 q w e a s
(integer) 5
127.0.0.1:6379> sinterstore q3 q1 q2
(integer) 3
127.0.0.1:6379> smembers q3
1) "q"
2) "w"
3) "e"

SISMEMBER

sismember key member

Set IsMember

判断在集合中是否存在member;

存在返回1,不存在返回0。

1
2
3
4
5
6
7
8
127.0.0.1:6379> smembers q3
1) "q"
2) "w"
3) "e"
127.0.0.1:6379> sismember q3 w
(integer) 1
127.0.0.1:6379> sismember q3 t
(integer) 0

SMEMBERS

smembers key

返回集合中所有对象。

当sinter中只有一个key,则等价于sinter。

SMISMEMBER

smismember key member [member ...]

Set Multi Member

同时判断集合中是否存在多个指定的对象。

返回一个数组,数组中元素依次表示对象是否包含在集合中,1表示包含,0表示不包含。

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> smembers q3
1) "q"
2) "w"
3) "e"
127.0.0.1:6379> smismember q3 q w s d
1) (integer) 1
2) (integer) 1
3) (integer) 0
4) (integer) 0

SRANDMEMBER

SRANDMEMBER key [count]

Set RANdom Member

基数:集合中对象的数量。

随机取出集合中指定数量的对象;

  • 若count为正,返回count数量的对象,若集合基数小于count,则返回基数个对象;

  • 若count为负,返回count绝对值数量的对象,若集合基数小于count的绝对值,则仍旧返回count绝对值数量的对象。

  • 负数的count返回的对象中存在重复的对象

返回值:

  • 若有count属性,返回一个数组,若key不存在或为空,返回空数组;
  • 若没有count属性,返回一个对象,若key不存在或为空,返回nil。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
127.0.0.1:6379> smembers q1 # q1中所有对象
1) "q"
2) "w"
3) "r"
4) "e"
5) "t"
127.0.0.1:6379> srandmember q1 3 # q1中随机取出3个对象
1) "w"
2) "e"
3) "r"
127.0.0.1:6379> srandmember q1 10 # q1中随机取出10个对象,由于q1基数为5,所以取出5个对象
1) "q"
2) "w"
3) "r"
4) "e"
5) "t"
127.0.0.1:6379> srandmember q1 -3 # q1中随机取出 |-3| 个对象,负数count取出的内容中存在重复
1) "r"
2) "r"
3) "e"
127.0.0.1:6379> srandmember q1 -9 # |-9|大于基数5,取出9个对象,内有重复。
1) "w"
2) "q"
3) "w"
4) "w"
5) "e"
6) "q"
7) "w"
8) "e"
9) "q"

SUNION

sunion key [key ...]

返回多个集合的并集;

若key不存在视集合为空集;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
127.0.0.1:6379> smembers q1
1) "q"
2) "w"
3) "t"
4) "e"
5) "r"
127.0.0.1:6379> smembers q2
1) "q"
2) "w"
3) "e"
4) "s"
5) "a"
127.0.0.1:6379> sunion q1 q2
1) "q"
2) "w"
3) "t"
4) "e"
5) "s"
6) "a"
7) "r"

SUNIONSTORE

sunionstore destination key [key ...]

等价于sunion,不同的是,sunionstore会将并集的结果存放于destination中。

 评论