Redis基础命令

Redis基础命令

Generic:通用命令

1.DEL命令

1
DEL key [key ...]
  • 命令复杂度: 删除键的复杂度为 O(N),其中 N 是要删除的键的数量。如果要删除的键包含的不是string,那么该键的复杂度为 O(M),其中 M 是list、set、sorted set或hash中的元素数量。删除单个包含string的键的复杂度为 O(1)。
  • 删除操作: 指定的键会被删除。如果键不存在,则会被忽略。
  • 返回值: 命令执行后会返回一个整数回复,表示被删除的键的数量。
1
2
3
4
5
6
7
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> DEL key1 key2 key3
(integer) 2
redis>

2.EXISTS命令

1
EXISTS key [key ...]
  • 命令复杂度: 该命令的复杂度为O(N),其中N是要检查的键的数量。
  • 计数方式:如果在参数中多次提到同一个已存在的键,它将被多次计数。例如,如果somekey存在,那么EXISTS somekey somekey将返回2。
  • 返回值: 该命令返回指定参数中存在的键的数量。
1
2
3
4
5
6
7
8
9
10
11
redis> SET key1 "Hello"
"OK"
redis> EXISTS key1
(integer) 1
redis> EXISTS nosuchkey
(integer) 0
redis> SET key2 "World"
"OK"
redis> EXISTS key1 key2 nosuchkey
(integer) 2
redis>

3.EXPIRE命令

1
EXPIRE key seconds [NX | XX | GT | LT]
  • 命令复杂度: 该命令的复杂度为O(1)。

  • 键的超时:在Redis中,可以为键设置超时,超时后键会自动删除。使用超时的键通常被称为易失性键。

  • 持久化和重命名:使用PERSIST命令可以清除超时,将键转换为持久键。如果使用RENAME命令重命名键,关联的生存时间也会转移到新的键名。

  • 这个命令支持一组选项:

    • NX:仅当键没有到期时间时设置到期时间
    • XX:仅当键已经有到期时间时设置到期时间
    • GT:仅当新的到期时间大于当前到期时间时设置到期时间
    • LT:仅当新的到期时间小于当前到期时间时设置到期时间
  • 返回值:对于已设置过期时间的键,EXPIRE 命令会返回 0,并且不会改变其过期时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> SET mykey "Hello World"
"OK"
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 XX
(integer) 0
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 NX
(integer) 1
redis> TTL mykey
(integer) 10
redis>

4.KEYS命令

1
KEYS pattern
  • 命令复杂度: 该命令的复杂度为O(N),其中 N 是数据库中键的数量,假设数据库中的键名和给定的模式具有有限的长度。尽管该操作的时间复杂度为 O(N),但常数时间相当低。例如,运行在入门级笔记本电脑上的 Redis 可以在 40 毫秒内扫描一个包含 100 万个键的数据库。
  • 支持的 glob 风格模式:
    • h?llo 匹配 hello、hallo 和 hxllo
    • h*llo 匹配 hllo 和 heeeello
    • h[ae]llo 匹配 hello 和 hallo,但不匹配 hillo
    • h[^e]llo 匹配 hallo、hbllo,但不匹配 hello
    • h[a-b]llo 匹配 hallo 和 hbllo
  • 返回值:该命令返回与指定模式匹配的所有键。

[!WARNING]

警告:请谨慎使用 KEYS 命令,只在生产环境中极度小心地使用。当对大型数据库执行该命令时,可能会影响性能。此命令旨在用于调试和特殊操作,比如更改键空间布局。不要在常规应用程序代码中使用 KEYS。如果要在键空间的子集中查找键,考虑使用 SCANsets

1
2
3
4
5
6
7
8
9
10
11
12
redis> MSET firstname Jack lastname Stuntman age 35
"OK"
redis> KEYS *name*
1) "firstname"
2) "lastname"
redis> KEYS a??
1) "age"
redis> KEYS *
1) "age"
2) "firstname"
3) "lastname"
redis>

5.OBJECT ENCODING命令

1
OBJECT ENCODING key
  • 命令复杂度: 该命令的复杂度为O(1)。

  • Strings可以编码为:

    • raw:普通的字符串编码。
    • int:表示在 64 位有符号区间内的整数的字符串,以此方式编码以节省空间。
    • embstr:嵌入式字符串,是一个对象,其中内部的简单动态字符串是一个无法修改的字符串,分配在与redisObject本身相同的块中。embstr 可以是长度最多达到 OBJ_ENCODING_EMBSTR_SIZE_LIMIT44 字节的字符串。
  • Lists可以编码为:

    • linkedlist:简单的列表编码。不再使用,是一个旧的列表编码。
    • ziplist:Redis <= 6.2,用于小型列表的节省空间的编码。
    • listpack:Redis >= 7.0,用于小型列表的节省空间的编码。
    • quicklist:以 ziplists 或 listpacks 的 linkedlist 编码。
  • Sets可以编码为:

    • hashtable:普通的集合编码。
    • intset:用于仅由整数组成的小型集合的特殊编码。
    • listpack:Redis >= 7.2,用于小型集合的节省空间的编码。
  • Hashes可以编码为:

    • hashtable:普通的哈希编码。
    • ziplist:Redis <= 6.2,用于小型哈希的节省空间的编码。
    • listpack:Redis >= 7.0,用于小型哈希的节省空间的编码。
  • Sorted Sets可以编码为:

    • skiplist:普通的有序集合编码。
    • ziplist:Redis <= 6.2,用于小型有序集合的节省空间的编码。
    • listpack:Redis >= 7.0,用于小型有序集合的节省空间的编码。
  • Streams可以编码为:

    • stream:编码为 listpacks 的 radix 树。
  • 返回值:返回存储在 <key> 处的 Redis 对象的内部编码。

6.OBJECT FREQ命令

1
OBJECT FREQ key
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 限制:该命令仅在 maxmemory-policy 配置指令设置为 LFU 策略之一时才可用。
  • 返回值:该命令返回存储在 <key> 处的 Redis 对象的对数访问频率计数器

7.PERSIST命令

1
PERSIST key
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 作用:移除键上的现有超时,将键从易失性(设置了过期时间的键)变为持久性(不会过期的键,因为没有关联的超时)。
  • 返回值
    • 如果键不存在或没有关联的超时,则返回 0。
    • 如果超时已被移除,则返回 1。
1
2
3
4
5
6
7
8
9
10
11
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> PERSIST mykey
(integer) 1
redis> TTL mykey
(integer) -1
redis>

8.RENAME命令

1
RENAME key newkey
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 作用:将键重命名为 newkey。当键不存在时,它会返回错误。如果 newkey 已经存在,它将被覆盖。在这种情况下,RENAME 将执行一个隐式的 DEL 操作,因此,即使 RENAME 本身通常是一个常数时间的操作,如果被删除的键包含一个非常大的值,也可能会导致高延迟。

[!WARNING]

在集群模式下,key 和 newkey 必须位于相同的哈希槽中,这意味着在实践中,只有具有相同哈希标签的键才能在集群中可靠地重命名。

1
2
3
4
5
6
7
redis> SET mykey "Hello"
"OK"
redis> RENAME mykey myotherkey
"OK"
redis> GET myotherkey
"Hello"
redis>

9.SCAN命令

1
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
  • 命令复杂度: 该命令的复杂度为O(1),对于完整的迭代,包括足够的命令调用使游标返回到0,时间复杂度为 O(N),其中 N 是集合内的元素数量。
  • SCAN 命令及其紧密相关的命令 SSCAN、HSCAN 和 ZSCAN 用于逐步迭代一组元素:
    • SCAN 迭代当前选定的 Redis 数据库中的键集。
    • SSCAN 迭代集合类型的元素。
    • HSCAN 迭代哈希类型的字段及其关联的值。
    • ZSCAN 迭代有序集合类型的元素及其关联的分数。
  • 注意,SCAN、SSCAN、HSCAN 和 ZSCAN 的工作方式非常相似,因此本文档涵盖了这四个命令。然而,明显的区别是在 SSCAN、HSCAN 和 ZSCAN 的情况下,第一个参数是持有 SetHashSorted Set 值的键名。SCAN 命令不需要任何键名参数,因为它迭代当前数据库中的键,所以被迭代的对象是数据库本身。

[!WARNING]

由于这些命令允许增量迭代,每次只返回少量元素,因此它们可以在生产环境中使用,而不会像 KEYS 或 SMEMBERS 命令那样产生一些不利的影响,当对大型键集或元素集合调用时,可能会导致服务器阻塞很长时间(甚至几秒钟)。

然而,尽管像 SMEMBERS 这样的阻塞命令能够提供在给定时刻作为集合一部分的所有元素,但是 SCAN 系列命令只能对返回的元素提供有限的保证,因为在迭代过程中我们增量迭代的集合可能会发生变化。

SCAN 是基于游标的迭代器。这意味着在每次调用命令时,服务器都会返回一个更新后的游标,用户需要将其作为下一次调用中的游标参数使用。迭代从将游标设置为 0 开始,并在服务器返回的游标为 0 时终止。以下是 SCAN 迭代的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
redis 127.0.0.1:6379> scan 0
1) "17"
2) 1) "key:12"
2) "key:8"
3) "key:4"
4) "key:14"
5) "key:16"
6) "key:17"
7) "key:15"
8) "key:10"
9) "key:3"
10) "key:7"
11) "key:1"
redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
2) "key:18"
3) "key:0"
4) "key:2"
5) "key:19"
6) "key:13"
7) "key:6"
8) "key:9"
9) "key:11"

10.TTL命令

1
TTL key
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 返回值
    • 以秒为单位的 TTL。
    • 如果键存在但没有关联的到期时间,则返回 -1。
    • 如果键不存在,则返回 -2。
1
2
3
4
5
6
7
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis>

11.TYPE命令

1
TYPE key
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 返回值:返回存储在键中值的类型的字符串表示。可能返回的不同类型包括:string(字符串)、list(列表)、set(集合)、zset(有序集合)、hash(哈希)和 stream(流)。
1
2
3
4
5
6
7
8
9
10
11
12
13
redis> SET key1 "value"
"OK"
redis> LPUSH key2 "value"
(integer) 1
redis> SADD key3 "value"
(integer) 1
redis> TYPE key1
"string"
redis> TYPE key2
"list"
redis> TYPE key3
"set"
redis>

12.UNLINK命令

1
UNLINK key [key ...]
  • 命令复杂度:每次删除键都是 O(1)的时间复杂度,无论其大小如何。然后,命令会在不同的线程中执行 O(N) 的工作以回收内存,其中 N 是被删除对象所包含的元素数量。
  • 作用:该命令与 DEL 非常相似,它会删除指定的键。就像 DEL 一样,如果键不存在,则会被忽略。然而,该命令会在不同的线程中执行实际的内存回收,因此它不会阻塞,而 DEL 会。这就是命令名称的由来:该命令只是从键空间中取消链接键。实际的删除操作会稍后以异步方式进行。
  • 返回值:返回已取消链接的键的数量。
1
2
3
4
5
6
7
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> UNLINK key1 key2 key3
(integer) 2
redis>

String:字符串命令

1.SET命令

1
SET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL]
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 作用:将键设置为保存字符串值。如果键已经保存了一个值,则无论其类型如何都会被覆盖。在成功的 SET 操作中,与键关联的任何先前的过期时间都将被丢弃。
  • SET 命令支持一组选项,修改其行为:
    • EX seconds:设置指定的到期时间,单位为秒(正整数)。
    • PX milliseconds:设置指定的到期时间,单位为毫秒(正整数)。
    • EXAT timestamp-seconds:设置键在指定的 Unix 时间点到期,单位为秒(正整数)。
    • PXAT timestamp-milliseconds:设置键在指定的 Unix 时间点到期,单位为毫秒(正整数)。
    • NX:仅当键不存在时设置键。
    • XX:仅当键已存在时设置键。
    • KEEPTTL:保留与键关联的到期时间。
    • GET:返回键处存储的旧字符串值,如果键不存在,则返回 nil。如果键处存储的值不是字符串,则返回错误并且 SET 操作中止。
1
2
3
4
5
6
7
redis> SET mykey "Hello"
"OK"
redis> GET mykey
"Hello"
redis> SET anotherkey "will expire in a minute" EX 60
"OK"
redis>

2.GET命令

1
GET key
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 返回值:获取键的值。如果键不存在,则返回特殊值 nil。如果存储在键处的值不是字符串,则返回错误,因为 GET 只处理字符串值。
1
2
3
4
5
6
7
redis> GET nonexisting
(nil)
redis> SET mykey "Hello"
"OK"
redis> GET mykey
"Hello"
redis>

3.MSET命令

1
MSET key value [key value ...]
  • 命令复杂度: 该命令的复杂度为O(N),其中 N 是键值对的个数。
  • 作用:将给定的键设置为它们各自的值。MSET 将现有的值替换为新值,就像普通的 SET 一样。如果不想覆盖现有值,请参见 MSETNX。

MSET 是原子的,因此所有给定的键都会同时设置。客户端无法看到某些键已更新而其他键保持不变。

1
2
3
4
5
6
7
redis> MSET key1 "Hello" key2 "World"
"OK"
redis> GET key1
"Hello"
redis> GET key2
"World"
redis>

4.MGET命令

1
MGET key [key ...]
  • 命令复杂度: 该命令的复杂度为O(N),其中 N 是取出的键值对的个数。
  • 返回值:返回所有指定键的值。对于每个不持有字符串值或不存在的键,都返回特殊值 nil。因此,该操作永远不会失败。
1
2
3
4
5
6
7
8
9
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> MGET key1 key2 nonexisting
1) "Hello"
2) "World"
3) (nil)
redis>

5.INCR命令

1
INCR key
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 作用:将存储在键处的数字增加一。如果键不存在,则在执行操作之前将其设置为 0。如果键包含错误类型的值或包含无法表示为整数的字符串,则返回错误。此操作仅限于 64 位有符号整数。
  • 返回值:返回递增后的整数值。

注意:这是一个字符串操作,因为 Redis 没有专门的整数类型。存储在键处的字符串被解释为一个十进制 64 位有符号整数来执行操作。Redis 使用int编码方案表示整数,因此对于实际保存整数的字符串值,存储字符串表示形式的整数不会产生额外开销。

1
2
3
4
5
6
7
redis> SET mykey "10"
"OK"
redis> INCR mykey
(integer) 11
redis> GET mykey
"11"
redis>

6.INCRBY命令

1
INCRBY key increment
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 作用:将存储在键处的数字增加指定的增量。如果键不存在,则在执行操作之前将其设置为 0。如果键包含错误类型的值或包含无法表示为整数的字符串,则返回错误。此操作仅限于 64 位有符号整数。
1
2
3
4
5
redis> SET mykey "10"
"OK"
redis> INCRBY mykey 5
(integer) 15
redis>

7.INCRBYFLOAT命令

1
INCRBYFLOAT key increment
  • 命令复杂度: 该命令的复杂度为O(1)。

  • 作用:将存储在键中的表示浮点数的字符串按指定的增量递增。通过使用负的增量值,结果是将键处存储的值递减。如果键不存在,则在执行操作之前将其设置为 0。如果发生以下条件之一,则返回错误:

    • 键包含错误类型的值(不是字符串)。
    • 当前键内容或指定的增量无法解析为双精度浮点数。

    如果命令成功,则将新的递增值存储为键的新值(替换旧值),并作为字符串返回给调用者。

    字符串键中已包含的值和递增参数都可以选择以指数表示法提供,但是在递增之后计算的值始终以相同的格式存储,即一个整数数字,后跟(如果需要)一个点,以及表示数字小数部分的变长数字。尾随的零总是被删除。

1
2
3
4
5
6
7
8
9
10
11
redis> SET mykey 10.50
"OK"
redis> INCRBYFLOAT mykey 0.1
"10.6"
redis> INCRBYFLOAT mykey -5
"5.6"
redis> SET mykey 5.0e3
"OK"
redis> INCRBYFLOAT mykey 2.0e2
"5200"
redis>

8.STRLEN命令

1
STRLEN key
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 返回值:返回存储在键处的字符串值的长度。当键持有非字符串值时,返回错误。
1
2
3
4
5
6
7
redis> SET mykey "Hello world"
"OK"
redis> STRLEN mykey
(integer) 11
redis> STRLEN nonexisting
(integer) 0
redis>

Hash:哈希命令

1.HSET命令

1
HSET key field value [field value ...]
  • 命令复杂度:每添加一个键值对的时间复杂度为 O(1),因此当命令以多个键值对调用时,添加 N 个键值对的时间复杂度为 O(N)。
  • 作用:该命令将覆盖哈希中存在的指定字段的值。如果键不存在,则创建一个持有哈希的新键。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
redis> HSET myhash field1 "Hello"
(integer) 1
redis> HGET myhash field1
"Hello"
redis> HSET myhash field2 "Hi" field3 "World"
(integer) 2
redis> HGET myhash field2
"Hi"
redis> HGET myhash field3
"World"
redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "Hi"
5) "field3"
6) "World"
redis>

2.HGET命令

1
HGET key field
  • 命令复杂度: 该命令的复杂度为O(1)。
  • 返回值:返回 key 所对应的 hash 结构的 field 字段的值。
1
2
3
4
5
6
7
redis> HSET myhash field1 "foo"
(integer) 1
redis> HGET myhash field1
"foo"
redis> HGET myhash field2
(nil)
redis>

3.HGETALL命令

1
HGETALL key
  • 命令复杂度: 该命令的时间复杂度为 O(N),其中 N 是哈希表的大小。
  • 返回值:返回存储在键中的哈希表的所有字段和值。在返回的值中,每个字段名都跟随其值,因此回复的长度是哈希表大小的两倍。
1
2
3
4
5
6
7
8
9
10
redis> HSET myhash field1 "Hello"
(integer) 1
redis> HSET myhash field2 "World"
(integer) 1
redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"
redis>

4.HKEYS命令

1
HKEYS key
  • 命令复杂度: 该命令的时间复杂度为 O(N),其中 N 是哈希表的大小。
  • 返回值:返回存储在键中的哈希表中的所有字段名。
1
2
3
4
5
6
7
8
redis> HSET myhash field1 "Hello"
(integer) 1
redis> HSET myhash field2 "World"
(integer) 1
redis> HKEYS myhash
1) "field1"
2) "field2"
redis>

5.HVALS命令

1
HVALS key
  • 命令复杂度: 该命令的时间复杂度为 O(N),其中 N 是哈希表的大小。
  • 返回值:返回存储在键中的哈希表中的所有字段值。
1
2
3
4
5
6
7
8
redis> HSET myhash field1 "Hello"
(integer) 1
redis> HSET myhash field2 "World"
(integer) 1
redis> HVALS myhash
1) "Hello"
2) "World"
redis>

6.应用场景:购物车

以用户 id 为 key,商品 id 为 field,商品数量为 value,恰好构成了购物车的3个要素,如下图所示。

img

涉及到的相关命令:

  • 添加商品:HSET cart:{userId} {productId} 1
  • 添加数量:HINCRBY cart:{userId} {productId} 1
  • 商品总数:HLEN cart:{userId}
  • 删除商品:HDEL cart:{userId} {productId}
  • 获取购物车所有商品:HGETALL cart:{userId}

当前仅仅是将商品ID存储到了Redis中,在回显商品显示信息时还需要回表查数据库,获取完整的商品信息。

List:列表命令

1.LPUSH命令

1
LPUSH key element [element ...]
  • 命令复杂度:每添加一个元素的时间复杂度为 O(1),因此当命令以多个参数调用时,添加 N 个元素的时间复杂度为 O(N)。

  • 作用:将所有指定的值插入到存储在键中的列表的头部。如果键不存在,则在执行推送操作之前将其创建为空列表。当键包含的值不是列表时,返回错误。

1
2
3
4
5
6
7
8
redis> LPUSH mylist "world"
(integer) 1
redis> LPUSH mylist "hello"
(integer) 2
redis> LRANGE mylist 0 -1
1) "hello"
2) "world"
redis>

2.LPOP命令

1
LPOP key [count]
  • 命令复杂度:该命令的时间复杂度为 O(N),其中 N 是返回元素的数量。
  • 作用:移除并返回存储在键中的列表的第一个元素。默认情况下,该命令从列表开头弹出单个元素。当提供可选的 count 参数时,返回的结果将包含最多 count 个元素,取决于列表的长度。
1
2
3
4
5
6
7
8
9
10
11
redis> RPUSH mylist "one" "two" "three" "four" "five"
(integer) 5
redis> LPOP mylist
"one"
redis> LPOP mylist 2
1) "two"
2) "three"
redis> LRANGE mylist 0 -1
1) "four"
2) "five"
redis>

3.LRANGE命令

1
LRANGE key start stop
  • 命令复杂度:该命令的时间复杂度为 O(S+N),其中 S 是 start 偏移量与头部的距离(针对小型列表)或 start 偏移量与最近的头尾的距离(针对大型列表,加快遍历速度),N 是范围内元素的数量。
  • 返回值:返回存储在键中的列表的指定元素。起始偏移量和停止偏移量是从零开始的索引,其中 0 表示列表的第一个元素(列表的头部),1 表示下一个元素,依此类推。这些偏移量也可以是负数,表示从列表末尾开始的偏移量。例如,-1 表示列表的最后一个元素,-2 表示倒数第二个元素,依此类推。

超出范围的索引不会产生错误。如果起始索引大于列表的末尾,则返回一个空列表。如果停止索引大于列表的实际末尾,Redis 将把它视为列表的最后一个元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
redis> RPUSH mylist "one"
(integer) 1
redis> RPUSH mylist "two"
(integer) 2
redis> RPUSH mylist "three"
(integer) 3
redis> LRANGE mylist 0 0
1) "one"
redis> LRANGE mylist -3 2
1) "one"
2) "two"
3) "three"
redis> LRANGE mylist -100 100
1) "one"
2) "two"
3) "three"
redis> LRANGE mylist 5 10
(empty array)
redis>

4.LSET命令

1
LSET key index element
  • 命令复杂度:该命令的时间复杂度为 O(N),其中 N 是列表的长度。将列表的第一个或最后一个元素设置为 O(1)。

  • 作用:将列表中索引位置的元素设置为指定的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
redis> RPUSH mylist "one"
(integer) 1
redis> RPUSH mylist "two"
(integer) 2
redis> RPUSH mylist "three"
(integer) 3
redis> LSET mylist 0 "four"
"OK"
redis> LSET mylist -2 "five"
"OK"
redis> LRANGE mylist 0 -1
1) "four"
2) "five"
3) "three"
redis>

5.LREM命令

1
LREM key count element
  • 命令复杂度:该命令的时间复杂度为 O(N+M),其中 N 是列表长度,M 是删除元素数量。
  • 从存储在键中的列表中移除前 count 次出现的与指定元素相等的元素。count 参数影响操作的方式如下:
    • count > 0从头到尾移除与元素相等的元素。
    • count < 0从尾到头移除与元素相等的元素。
    • count = 0:移除所有与元素相等的元素。

注意,不存在的键被视为空列表,因此当键不存在时,该命令将始终返回 0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
redis> RPUSH mylist "hello"
(integer) 1
redis> RPUSH mylist "hello"
(integer) 2
redis> RPUSH mylist "foo"
(integer) 3
redis> RPUSH mylist "hello"
(integer) 4
redis> LREM mylist -2 "hello"
(integer) 2
redis> LRANGE mylist 0 -1
1) "hello"
2) "foo"
redis>

6.LMPOP命令

1
LMPOP numkeys key [key ...] <LEFT | RIGHT> [COUNT count]
  • 命令复杂度:该命令的时间复杂度为 O(N+M),其中 N 是提供的key的个数,M 是返回元素的数量。
  • 作用:根据传递的参数,从第一个非空列表的左侧或右侧弹出元素。返回的元素数量受到非空列表长度和 count 参数(默认为 1)中较小者的限制。
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
34
35
36
37
38
39
40
41
42
43
44
redis> LMPOP 2 non1 non2 LEFT COUNT 10
(error) object of type 'NoneType' has no len()
redis> LPUSH mylist "one" "two" "three" "four" "five"
(integer) 5
redis> LMPOP 1 mylist LEFT
1) "mylist"
2) 1) "five"
redis> LRANGE mylist 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
redis> LMPOP 1 mylist RIGHT COUNT 10
1) "mylist"
2) 1) "one"
2) "two"
3) "three"
4) "four"
redis> LPUSH mylist "one" "two" "three" "four" "five"
(integer) 5
redis> LPUSH mylist2 "a" "b" "c" "d" "e"
(integer) 5
redis> LMPOP 2 mylist mylist2 right count 3
1) "mylist"
2) 1) "one"
2) "two"
3) "three"
redis> LRANGE mylist 0 -1
1) "five"
2) "four"
redis> LMPOP 2 mylist mylist2 right count 5
1) "mylist"
2) 1) "four"
2) "five"
redis> LMPOP 2 mylist mylist2 right count 10
1) "mylist2"
2) 1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
redis> EXISTS mylist mylist2
(integer) 0
redis>

7.BLPOP命令

1
BLPOP key [key ...] timeout
  • 命令复杂度:该命令的时间复杂度为 O(N),其中 N 是提供的key的个数。
  • 作用:BLPOP 是一个阻塞列表弹出原语。它是 LPOP 的阻塞版本,因为当给定列表中没有任何元素可弹出时,它会阻塞连接。从第一个非空列表的头部弹出一个元素,并按照给定的顺序检查给定的键。

8.LMOVE命令

1
LMOVE source destination <LEFT | RIGHT> <LEFT | RIGHT>
  • 命令复杂度:该命令的时间复杂度为 O(1)。
  • 作用:原子地返回并移除存储在源列表(source)中的第一个/最后一个元素(头部/尾部取决于 wherefrom 参数),并将该元素推送到存储在目标列表(destination)中的第一个/最后一个位置(头部/尾部取决于 whereto 参数)。例如:假设源列表(source)包含列表 a、b、c,目标列表(destination)包含列表 x、y、z。执行 LMOVE source destination RIGHT LEFT 将导致源列表包含 a、b,目标列表包含 c、x、y、z。

如果源列表不存在,则返回值为 nil,且不执行任何操作。如果源列表和目标列表相同,则操作相当于从列表中移除第一个/最后一个元素,并将其推送为列表的第一个/最后一个元素,因此可以将其视为列表旋转命令(或者如果 wherefrom 与 whereto 相同,则视为无操作)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
redis> RPUSH mylist "one"
(integer) 1
redis> RPUSH mylist "two"
(integer) 2
redis> RPUSH mylist "three"
(integer) 3
redis> LMOVE mylist myotherlist RIGHT LEFT
"three"
redis> LMOVE mylist myotherlist LEFT RIGHT
"one"
redis> LRANGE mylist 0 -1
1) "two"
redis> LRANGE myotherlist 0 -1
1) "three"
2) "one"
redis>

9.应用场景:可靠队列

Redis通常被用作消息服务器来实现后台作业处理或其他类型的消息任务。一个简单的队列通常通过在生产者端将值推入列表中来获得,然后在消费者端使用RPOP(使用轮询)或BRPOP(如果客户端更适合使用阻塞操作)来等待这些值。然而,在这种情况下,获得的队列是不可靠的,因为消息可能会丢失,例如在存在网络问题或者在消息被接收但仍需处理时消费者崩溃。

LMOVE(或其阻塞变体BLMOVE)提供了一种避免这个问题的方法:消费者获取消息的同时将其推送到一个处理列表中,一旦消息已经被成功处理,可以使用LREM命令从处理列表中删除消息。一个额外的客户端可以监视处理列表中停留时间过长的项目,并在需要时将这些超时的项目再次推送回队列中。

Set:集合命令

1.SADD命令

1
SADD key member [member ...]
  • 命令复杂度:每次添加元素的时间复杂度为O(1),因此当命令同时使用多个参数调用时,添加N个元素的时间复杂度为O(N)。
  • 作用:将指定的成员添加到存储在键中的集合中。已经是该集合成员的指定成员将被忽略。如果键不存在,则在添加指定成员之前将创建一个新的集合。
1
2
3
4
5
6
7
8
9
10
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "Hello"
2) "World"
redis>

2.SREM命令

1
SREM key member [member ...]
  • 命令复杂度:该命令的时间复杂度为 O(N),其中 N 是要移除的元素数量。
  • 作用;该命令从存储在 key 中的集合中移除指定的成员。被指定移除的成员如果不是该集合的成员,则被忽略。如果 key 不存在,那么它会被视为空集合,并且该命令返回 0。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
redis> SADD myset "one"
(integer) 1
redis> SADD myset "two"
(integer) 1
redis> SADD myset "three"
(integer) 1
redis> SREM myset "one"
(integer) 1
redis> SREM myset "four"
(integer) 0
redis> SMEMBERS myset
1) "two"
2) "three"
redis>

3.SCARD命令

1
SCARD key
  • 命令复杂度:该命令的时间复杂度为 O(1)。
  • 返回值:返回存储在 key 对应的集合的元素数量。
1
2
3
4
5
6
7
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SCARD myset
(integer) 2
redis>

4.SISMEMBER命令

1
SISMEMBER key member
  • 命令复杂度:该命令的时间复杂度为 O(1)。
  • 返回值:返回 member 是否是存储在 key 中的集合的成员。
1
2
3
4
5
6
7
redis> SADD myset "one"
(integer) 1
redis> SISMEMBER myset "one"
(integer) 1
redis> SISMEMBER myset "two"
(integer) 0
redis>

5.SINTER命令

1
SINTER key [key ...]
  • 命令复杂度:在最坏的情况下,时间复杂度为 O(N*M),其中 N 是最小集合的基数,而 M 是集合的数量。
  • 返回值:返回由所有给定集合的交集产生的集合的成员。
1
2
3
4
5
6
7
8
9
10
11
12
13
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SINTER key1 key2
1) "c"
redis>

6.SUNION命令

1
SUNION key [key ...]
  • 命令复杂度:该命令的时间复杂度为 O(1),其中 N 是给定的所有集合的元素数量之和。
  • 返回值:返回由所有给定集合的并集产生的集合的成员。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SUNION key1 key2
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
redis>

7.SDIFF命令

1
SDIFF key [key ...]
  • 命令复杂度:该命令的时间复杂度为 O(1),其中 N 是给定的所有集合的元素数量之和。
  • 返回值:返回第一个集合与所有后续集合之间差异的成员。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
redis> SADD key1 "a"
(integer) 1
redis> SADD key1 "b"
(integer) 1
redis> SADD key1 "c"
(integer) 1
redis> SADD key2 "c"
(integer) 1
redis> SADD key2 "d"
(integer) 1
redis> SADD key2 "e"
(integer) 1
redis> SDIFF key1 key2
1) "a"
2) "b"
redis>

8.应用场景:抽奖活动

存储某活动中中奖的用户名 ,Set 类型因为有去重功能,可以保证同一个用户不会中奖两次。

key 为抽奖活动名,value 为员工名称,把所有员工名称放入抽奖箱:

1
SADD Tom Jerry John Sean Marry Lindy Sary Mark

如果允许重复中奖,可以使用 SRANDMEMBER 命令。

image-20240901195902537

如果不允许重复中奖,可以使用 SPOP 命令。

image-20240901195929408

Sorted Set:有序集合命令

1.ZADD命令

1
ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member   ...]
  • 命令复杂度:每添加一个元素的时间复杂度为O(log(N)),其中N是有序集合中的元素数量。
  • 作用:该命令将所有指定的成员以及指定的分数添加到存储在键为key的有序集合中。可以指定多个分数/成员对。如果指定的成员已经是有序集合的成员,则更新其分数,并将元素重新插入到正确的位置以确保正确的排序。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 1 "uno"
(integer) 1
redis> ZADD myzset 2 "two" 3 "three"
(integer) 2
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
redis>

2.ZREM命令

1
ZREM key member [member ...]
  • 命令复杂度:该命令的时间复杂度为O(M*log(N)),其中 N 是有序集合中元素的数量,M 是操作中被移除的元素数量。
  • 作用:该命令从存储在键为key的有序集合中移除指定的成员。不存在的成员将被忽略。当键存在但不持有有序集合时,会返回错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREM myzset "two"
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "one"
2) "1"
3) "three"
4) "3"
redis>

3.ZSCORE命令

1
ZSCORE key member
  • 命令复杂度:该命令的时间复杂度为O(1)。
  • 作用:返回键为key的有序集合中成员member的分数。
1
2
3
4
5
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZSCORE myzset "one"
"1"
redis>

4.ZRANK命令

1
ZRANK key member [WITHSCORE]
  • 命令复杂度:该命令的时间复杂度为O(log(N))。
  • 作用:该命令返回存储在键为key的有序集合中的成员的排名,其中分数从低到高排序。排名是从0开始的,这意味着具有最低分数的成员的排名为0。

5.ZCARD命令

1
ZCARD key
  • 命令复杂度:该命令的时间复杂度为O(1)。
  • 作用:该命令返回存储在键为key的有序集合中的元素数量。
1
2
3
4
5
6
7
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZCARD myzset
(integer) 2
redis>

6.ZCOUNT命令

1
ZCOUNT key min max
  • 命令复杂度:该命令的时间复杂度为O(log(N)),其中 N 是有序集合中元素的数量。
  • 作用:该命令返回键为key的有序集合中分数介于min和max之间的元素数量。

注意:该命令的复杂度仅为O(log(N)),因为它使用元素的排名(参见ZRANK)来获取范围的概念。因此,无需按范围大小进行工作。

1
2
3
4
5
6
7
8
9
10
11
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZCOUNT myzset -inf +inf
(integer) 3
redis> ZCOUNT myzset (1 3
(integer) 2
redis>

7.ZINCRBY命令

1
ZINCRBY key increment member
  • 命令复杂度:该命令的时间复杂度为O(log(N)),其中 N 是有序集合中元素的数量。
  • 作用:将存储在键为key的有序集合中的成员的分数增加increment。如果成员不存在于有序集合中,则将其添加到有序集合中,并将increment作为其分数(就好像其先前的分数为0.0)。如果键不存在,则创建一个具有指定成员作为唯一成员的新有序集合。
1
2
3
4
5
6
7
8
9
10
11
12
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZINCRBY myzset 2 "one"
"3"
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "two"
2) "2"
3) "one"
4) "3"
redis>

8.ZRANGE命令

1
ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count]   [WITHSCORES]
  • 命令复杂度:该命令的时间复杂度为O(log(N)+M),其中 N 是有序集合中元素的数量,M 是返回的元素数量。

  • 返回值:返回存储在指定键处的有序集合中指定范围的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
redis> ZADD myzset 1 "one" 2 "two" 3 "three"
(integer) 3
redis> ZRANGE myzset 0 -1
1) "one"
2) "two"
3) "three"
redis> ZRANGE myzset 2 3
1) "three"
redis> ZRANGE myzset -2 -1
1) "two"
2) "three"
redis> ZRANGE myzset 0 1 WITHSCORES
1) "one"
2) "1"
3) "two"
4) "2"
redis> ZRANGE myzset (1 +inf BYSCORE LIMIT 1 1
1) "three"
redis>

9.ZREMRANGEBYSCORE命令

1
ZREMRANGEBYSCORE key min max
  • 命令复杂度:该命令的时间复杂度为O(log(N)+M),其中 N 是有序集合中元素的数量,M 是操作中被移除的元素数量。

  • 作用:移除存储在指定键处的有序集合中所有分数在min和max之间(包括min和max)的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZADD myzset 3 "three"
(integer) 1
redis> ZREMRANGEBYSCORE myzset -inf (2
(integer) 1
redis> ZRANGE myzset 0 -1 WITHSCORES
1) "two"
2) "2"
3) "three"
4) "3"
redis>

10.应用场景:排行榜

我们以博文点赞排名为例,小林发表了五篇博文,分别获得赞为 200、40、100、50、150。

image-20240901200635587

文章 arcticle:4 新增一个赞,可以使用 ZINCRBY 命令(为有序集合key中元素member的分值加上increment):

image-20240901200711465

查看某篇文章的赞数,可以使用 ZSCORE 命令(返回有序集合key中元素个数):

image-20240901200749975

获取小林文章赞数最多的 3 篇文章,可以使用 ZREVRANGE 命令(倒序获取有序集合 key 从start下标到stop下标的元素):

image-20240901200829472

获取小林 100 赞到 200 赞的文章,可以使用 ZRANGEBYSCORE 命令(返回有序集合中指定分数区间内的成员,分数由低到高排序):

image-20240901200906447

Transactions:事务命令

Redis事务允许将一组命令在单个步骤中执行,它们围绕着MULTIEXECDISCARDWATCH命令展开。Redis事务提供了两个重要的保证:

  1. 所有事务中的命令都是串行化的,按顺序执行。在Redis事务的执行过程中,不会为其他客户端发送的请求服务。这保证了命令作为单个隔离操作执行。
  2. EXEC命令触发执行事务中的所有命令,因此如果在事务上下文中的客户端在调用EXEC命令之前失去与服务器的连接,则不会执行任何操作。相反,如果调用了EXEC命令,则会执行所有操作。在使用AOF时,Redis确保使用单个write(2)系统调用将事务写入磁盘。但是,如果Redis服务器崩溃或以某种硬性方式被系统管理员终止,则可能仅注册部分操作。Redis将在重新启动时检测到此情况,并显示错误退出。使用redis-check-aof工具,可以修复追加模式文件,从而删除部分事务,以便服务器可以重新启动。

从版本2.2开始,Redis允许在以上两种保证的基础上提供额外的保证,以一种非常类似于检查并设置(CAS)操作的乐观锁定方式。

在Redis中,通过使用MULTI命令可以进入事务。该命令始终会回复OK。在此时,用户可以发出多个命令。而不是立即执行这些命令,Redis会将它们排队。一旦调用EXEC命令,所有命令都将执行。如果调用DISCARD命令,将清空事务队列并退出事务。

1
2
3
4
5
6
7
8
9
> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1

在执行EXEC之后发生的错误不会以特殊方式处理:即使在事务期间某个命令失败,所有其他命令仍将被执行

1
2
3
4
5
6
7
8
9
10
11
12
13
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
MULTI
+OK
SET a abc
+QUEUED
LPOP a
+QUEUED
EXEC
*2
+OK
-WRONGTYPE Operation against a key holding the wrong kind of value

WATCH用于在Redis事务中提供检查并设置(CAS)行为。被WATCH的键会被监视以侦测对它们的更改。如果在执行EXEC命令之前至少有一个被监视的键被修改,整个事务会中止,并且EXEC返回一个空回复来通知事务失败。

1
2
3
4
5
6
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

WATCH命令实际上是一个使EXEC变得有条件的命令:我们要求Redis仅在没有任何被WATCH的键被修改时执行事务。这包括客户端进行的修改,如写入命令,以及Redis本身进行的修改,如过期或驱逐。如果在键被WATCH和EXEC接收到之间被修改,则整个事务将被中止。

事务中的命令不会触发WATCH条件,因为它们只是排队,直到EXEC被发送。当调用EXEC时,所有键都将取消监视,无论事务是否中止。当客户端连接关闭时,所有键都将取消监视。

WATCH命令可以用来创建Redis原本不支持的新的原子操作的一个很好的例子是实现ZPOP,它是一个以原子方式从有序集合中弹出具有较低分数的元素。以下是最简单的实现方式:

1
2
3
4
5
WATCH zset
element = ZRANGE zset 0 0
MULTI
ZREM zset element
EXEC