Redis的数据类型

本文介绍了 Redis 的 5 种主要数据类型,包括字符串、散列、列表、集合和有序集合类型,详细阐述了每种类型的特点,并列举了相应的操作命令,如赋值、取值、增减元素等,为使用 Redis 进行数据存储和操作提供了参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

字符串类型

命令

1. 赋值与取值

2. 递增数字

3. 增加指定的整数

4. 减少指定的整数

5. 增加指定浮点数

6. 向尾部追加值

7. 获取字符串长度

8. 同时获得/设置多个键值

散列类型

命令

1. 赋值与取值

2. 判断字段是否存在

3. 当字段不存在时赋值

4. 增加数字

5. 删除字段

6. 只获取字段名或字段值

7. 获得字段数量

列表类型

命令

1. 向列表两端增加元素

2. 从列表两端弹出元素

3. 获取列表中元素的个数

4. 获得列表片段

5. 删除列表中指定的值

6. 获得/设置指定索引的元素值

7. 只保留列表指定片段

8. 向列表中插入元素

集合类型

命令

1. 增加/删除元素

2. 获得集合中的所有元素

3. 判断元素是否在集合中

4. 集合间运算

5. 获得集合中元素个数

6. 随机获得集合中的元素

7. 从集合中弹出一个元素

有序集合类型

命令

1. 增加元素

2. 获得元素的分数

3. 获得排名在某个范围的元素列表

4. 获得指定分数范围的元素

5. 增加某个元素的分数

6. 获得集合中元素的数量

7. 获得指定分数范围内的元素个数

8. 删除一个或多个元素

9. 按照排名范围删除元素

10. 按照分数范围删除元素

11. 获得元素的排名


Redis 有5种主要的数据类型,这5种数据类型分别是:string(字符串类型)、hash(散列类型)、list(列表类型)、set(集合类型)、zset(有序集合类型)。本文将介绍这5种数据类型及相应的命令。

字符串类型

字符串类型是 Redis 中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据。我们可以用它存储用户的邮箱、手机号、JSON化的对象等。一个字符串类型键允许存储的数据的最大容量是512MB。

字符串类型是其它 4 种数据类型的基础,其它数据类型和字符串类型的差别从某种角度来说只是组织字符串的形式不同。例如,列表类型是以列表的形式组织字符串,而集合类型是以集合的形式组织字符串。

命令

1. 赋值与取值

SET key value
GET key

SET 和 GET 是 Redis 中最简单的两个命令,它们实现的功能和编程语言中的读写变量相似,如 key = “hello” 在 Redis 中是这样表示的:

127.0.0.1:6379> SET key hello
OK

想要读取键值也很简单,只需要使用 GET 命令就可以了:

127.0.0.1:6379> GET key
"hello"

当键不存在时,会返回空结果。

2. 递增数字

INCR key

前文说过字符串类型可以存储任何形式的字符串,当存储的字符串是整数形式时,Redis 提供了一个实用的命令 INCR,其作用是让当前键值递增,并返回递增后的值,用法为:

127.0.0.1:6379> INCR num
(integer) 1
127.0.0.1:6379> INCR num
(integer) 2

当操作的键不存在时会默认键值为0,所以第一次递增后的结果是1。当键值不是整数时 Redis 会提示错误:

127.0.0.1:6379> SET test abc
OK
127.0.0.1:6379> INCR test
(error) ERR value is not an integer or out of range

3. 增加指定的整数

INCRBY key increment

INCRBY 命令与 INCR 命令基本一样,只不过前者可以通过 increment 参数指定一次增加的数值,如:

127.0.0.1:6379> INCRBY bar 2
(integer) 2
127.0.0.1:6379> INCRBY bar 3
(integer) 5

4. 减少指定的整数

DECR key
DECRBY key decrement

DECR 命令与 DECRBY 命令用法相同,只不过是让键值递减,例如:

127.0.0.1:6379> DECR bar
(integer) 4

而 DECRBY 命令的作用不用介绍想必已经有读者可以猜到其功能了,该命令与 INCRBY 命令是相反的操作。DECRBY key 5 相当于 INCRBY key -5。

5. 增加指定浮点数

INCRBYFLOAT key increment

INCRBYFLOAT 命令类似 INCRBY 命令,区别是前者可以递增一个双精度浮点数(存在精度误差),如:

127.0.0.1:6379> INCRBYFLOAT bar 2.7
"6.70000000000000018"
127.0.0.1:6379> INCRBYFLOAT bar 5E+4
"50006.69999999999708962"

6. 向尾部追加值

APPEND key value

APPEND 作用是向键值的末尾追加 value。如果键不存在则将该键的值设置为 value。返回值是追加后字符串的总长度。如:

127.0.0.1:6379> SET key hello
OK
127.0.0.1:6379> APPEND key " world!"
(integer) 12

此时 key 的值是 “hello world!”。APPEND 命令的第二个参数加了双引号,原因是该参数保护空格。

7. 获取字符串长度

STRLEN key

STRLEN 命令返回键值的长度,如果键不存在则返回0。例如:

127.0.0.1:6379> SET key "hello world!"
OK
127.0.0.1:6379> STRLEN key
(integer) 12
127.0.0.1:6379> SET key abcd123
OK
127.0.0.1:6379> STRLEN key
(integer) 7

8. 同时获得/设置多个键值

MGET key [key ...]
MSET key value [key value ...]

MGET/MSET 与 GET/SET 相似,不过 MGET/MSET 可以同时获得/设置多个键的键值。例如:

127.0.0.1:6379> MSET key1 v1 key2 v2 key3 v3
OK
127.0.0.1:6379> GET key2
"v2"
127.0.0.1:6379> MGET key1 key3
1) "v1"
2) "v3"

散列类型

Redis 是采用字典结构以键值对的形式存储数据的,而散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射,但字段值只能是字符串,不支持其它数据类型,换句话说,散列类型不能嵌套其它的数据类型。一个散列类型可以包含至多 2³²-1 个字段。

散列类型适合存储对象:使用对象类别和 ID 构成键名,使用字段表示对象的属性,而字段值则存储属性值。例如要存储ID为2的手机对象,可以分别使用名为color、name和price的3个字段来存储该手机的颜色、名称和价格。存储结构下图所示。

如果我们要在关系数据库中存储手机对象,那么存储结构应该会像下面展示的表格一样。

IDcolornameprice
1黑色红米999
2白色Vivo1999

数据是以二维表的形式存储的,这就要求所有的记录都拥有同样的属性,无法单独为某条记录增减属性。如果想为 ID 为 1 的手机增加生产日期属性,就需要把数据表更改为如下表所示的结构。

IDcolornamepricedate
1黑色红米9992023-10-21
2白色Vivo1999

对于ID为2的记录而言date字段是冗余的。可想而知当不同的记录需要不同的属性时,表的字段数量会越来越多以至于难以维护。而且当使用 ORM 将关系数据库中的对象实体映射成程序中的实体时,修改表的结构往往意味着要中断服务。为了防止这些问题,在关系数据库中存储这种半结构化数据还需要额外的表才行。

而 Redis 的散列类型则不存在这个问题。虽然我们在图中描述了手机对象的存储结构,但是这个结构只是人为约定的,Redis 并不要求每个键都依据此结构存储,我们完全可以为任何键增减字段而不影响其它键。

命令

1. 赋值与取值

HSET key field value
HGET key field
HMSET key field value [field value ...]
HMGET key field [field ...]
HGETALL key

HSET 命令用来给字段赋值,而 HGET 命令用来获得字段的值。用法如下:

127.0.0.1:6379> HSET phone price 1999
(integer) 1
127.0.0.1:6379> HSET phone name Vivo
(integer) 1
127.0.0.1:6379> HGET phone name
"Vivo"
127.0.0.1:6379> HGET phone price
"1999"

HSET 命令的方便之处在于不区分插入和更新操作,这意味着修改数据时不用事先判断字段是否存在来决定要执行的是插入操作还是更新操作。当执行的插入操作时(即之前字段不存在)HSET 命令会返回1,当执行的是更新操作时(即之前字段已经存在)HSET 命令会返回0。当键本身不存在时,HSET 命令还会自动建立它。

当需要同时设置多个字段的值时,可以使用 HMSET 命令。例如,下面两条语句

HSET key field1 value1
HSET key field2 value2

可以用 HSMSET 命令改写成

HMSET key field1 value1 field2 value2

相应地,HMGET 命令可以同时获得多个字段的值:

127.0.0.1:6379> HMGET phone name price
1) "Vivo"
2) "1999"

如果想获取键值所有字段和字段值却不知道键中有哪些字段时,可以使用 HGETALL 命令。如:

127.0.0.1:6379> HGETALL phone
1) "price"
2) "1999"
3) "name"
4) "Vivo"

返回的结果是字段和字段值组成的列表。

2. 判断字段是否存在

HEXISTS key field

HEXISTS 命令用来判断一个字段是否存在。如果存在则返回 1,否则返回 0(如果键不存在也会返回 0)。

127.0.0.1:6379> HEXISTS phone color
(integer) 0
127.0.0.1:6379> HSET phone color white
(integer) 1
127.0.0.1:6379> HEXISTS phone color
(integer) 1

3. 当字段不存在时赋值

HSETNX key field value

HSETNX 命令与 HSET 命令类似,区别在于如果字段已经存在,HSETNX 命令将不执行任何操作。

4. 增加数字

HINCRBY key field increment

在字符串类型的命令内容中我们介绍了 INCRBY 命令,HINCRBY 命令与之类似,可以使字段值增加指定的整数。散列类型没有 HINCR 命令,但是可以通过 HINCRBY key field 1 来实现。

HINCRBY 命令的示例如下:

127.0.0.1:6379> HINCRBY student score 60
(integer) 60

之前 student 键不存在,HINCRBY 命令会自动建立该键并默认 score 字段在执行命令前的值为“0”。命令的返回值是增值后的字段值。

5. 删除字段

HDEL key field [field ...]

HDEL 命令可以删除一个或多个字段,返回值是被删除的字段个数:

127.0.0.1:6379> HDEL phone price
(integer) 1
127.0.0.1:6379> HDEL phone price
(integer) 0

6. 只获取字段名或字段值

HKEYS key
HVALS key

有时仅仅需要获取键中所有字段的名字而不需要字段值,那么可以使用 HKEYS 命令,就像这样:

127.0.0.1:6379> HKEYS phone
1) "name"
2) "color"

HVALS 命令与 HKEYS 命令相对应,HVALS 命令用来获得键中所有字段值,例如:

127.0.0.1:6379> HVALS phone
1) "Vivo"
2) "white"

7. 获得字段数量

HLEN key

例如:

127.0.0.1:6379> HLEN phone
(integer) 2

列表类型

列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素,或者获得列表的某一个片段。

列表类型内部是使用双向链表(double linked list)实现的,所以向列表两端添加元素的时间复杂度为 O(1),获取越接近两端的元素速度就越快。这意味着即使是一个有几千万个元素的列表,获取头部或尾部的10条记录也是极快的(和从只有20个元素的列表中获取头部或尾部的10条记录的速度是一样的)。不过使用链表的代价是通过索引访问元素比较慢。

这种特性使列表类型能非常快速地完成关系数据库难以应付的场景:如新闻网站的最新新闻,我们关心的只是最新的新闻,使用类别类型存储,即使最新新闻的总数达到了几千万条,获取其中最新的100条数据也是极快的。同样因为在两端插入记录的时间复杂度是 O(1),列表类型也适合用来记录日志,可以保证加入新日志的速度不会受到已有日志数量的影响。

与散列类型键最多能容纳的字段数量相同,一个列表类型键最多能容纳 2³²-1 个元素。

命令

1. 向列表两端增加元素

LPUSH key value [value ...]
RPUSH key value [value ...]

LPUSH 命令用来向列表左边增加元素,返回值表示增加元素后列表的长度。

127.0.0.1:6379> LPUSH nums 1
(integer) 1

这时 nums 键中的数据如下左图所示。LPUSH 命令还支持同时增加多个元素,例如:

127.0.0.1:6379> LPUSH nums 2 3
(integer) 3

LPUSH 会先向列表左边加入”2″,然后再加入”3″,所以此时 nums 键中的数据如下右图所示。

向列表右边增加元素则使用 RPUSH 命令,其用法和 LPUSH 命令一样:

127.0.0.1:6379> RPUSH nums 0 -1
(integer) 5

此时 nums 键中的数据如下图所示。

2. 从列表两端弹出元素

LPOP key
RPOP key

有进有出,LPOP 命令可以从列表左边弹出一个元素。LPOP 命令执行两步操作:第一步是将列表左边的元素从列表中移除,第二步是返回被移除的元素值。例如,从 nums 列表左边弹出一个元素(也就是”3″):

127.0.0.1:6379> LPOP nums
"3"

同样,RPOP 命令可以从列表右边弹出一个元素:

127.0.0.1:6379> RPOP nums
"-1"

结合上面 4 个命令可以使用列表类型来模拟栈和队列的操作:如果想把列表当做栈,则搭配使用 LPUSH 和 LPOP 或 RPUSH 和 RPOP,如果想当做队列,则搭配使用 LPUSH 和 RPOP 或 RPUSH 和 LPOP。

3. 获取列表中元素的个数

LLEN key

当键不存在时 LLEN 会返回 0:

127.0.0.1:6379> LLEN nums
(integer) 3

4. 获得列表片段

LRANGE key start stop

LRANGE 命令时列表类型最常用的命令之一,它能够获得列表中的某一片段。LRANGE 命令将返回索引从 start 到 stop 之间的所有元素(包含两端的元素)。与大多数人的猜测相同,Redis 的列表起始索引为 0:

127.0.0.1:6379> LRANGE nums 0 2
1) "2"
2) "1"
3) "0"

LRANGE 命令在取得列表片段的同时不会像 LPOP 一样删除该片段。

LRANGE 命令也支持负索引,表示从右边开始计算序数,如 “-1″ 表示最右边第一个元素,”-2″ 表示最右边第二个元素,依次类推:

127.0.0.1:6379> LRANGE nums -2 -1
1) "1"
2) "0"

显然,LRANGE nums 0 -1 可以获取列表中的所有元素。另外一些特殊情况如下。

  1. 如果 start 的索引位置比 stop 的索引位置靠后,则会返回空列表。
  2. 如果 stop 大于实际的索引范围,则会返回到列表最右边的元素:
127.0.0.1:6379> LRANGE nums 1 999
1) "1"
2) "0"

5. 删除列表中指定的值

LREM key count value

LREM 命令会删除列表中前 count 个值为 value 的元素,返回值是实际删除的元素个数。根据 count 值的不同,LREM 命令的执行方式会略有差异。

  1. 当 count > 0 时,LREM 命令会从列表左边开始删除前 count 个值为 value 的元素。
  2. 当 count < 0 时,LREM 命令会从列表右边开始删除前 |count| 个值为 value 的元素。
  3. 当 count = 0 时,LREM 命令会删除所有值为 value 的元素。例如:
127.0.0.1:6379> RPUSH nums 2
(integer) 4
127.0.0.1:6379> LRANGE nums 0 -1
1) "2"
2) "1"
3) "0"
4) "2"

# 从右边删除第一个值为"2"的元素 
127.0.0.1:6379> LREM nums -1 2
(integer) 1
127.0.0.1:6379> LRANGE nums 0 -1
1) "2"
2) "1"
3) "0"

6. 获得/设置指定索引的元素值

LINDEX key index
LSET key index value

如果要将列表类型当做数组来用,LINDEX 命令是必不可少的。LINDEX 命令用来返回指定索引的元素,索引从 0 开始。如:

127.0.0.1:6379> LINDEX nums 0
"2"

如果 index 是负数则表示从右边开始计算的索引,最右边元素的索引是 -1。例如:

127.0.0.1:6379> LINDEX nums -1
"0"

LSET 是另一个通过索引操作列表的命令,它会将索引为 index 的元素赋值为 value。例如:

127.0.0.1:6379> LSET nums 1 7
OK
127.0.0.1:6379> LINDEX nums 1
"7"

7. 只保留列表指定片段

LTRIM key start end

LTRIM 命令可以删除指定索引范围之外的所有元素,其指定列表范围的方法和 LRANGE 命令相同。就像这样:

127.0.0.1:6379> LRANGE nums 0 -1
1) "2"
2) "7"
3) "0"
127.0.0.1:6379> LTRIM nums 1 2
OK
127.0.0.1:6379> LRANGE nums 0 -1
1) "7"
2) "0"

8. 向列表中插入元素

LINSERT key BEFORE|AFTER pivot value

LINSERT 命令首先会在列表中从左到右查找值为 pivot 的元素,然后根据第二个参数是 BEFORE 还是 AFTER 来决定将 value 插入到该元素的前面还是后面。

LINSERT 命令的返回值是插入后列表的元素个数。示例如下:

127.0.0.1:6379> LRANGE nums 0 -1
1) "7"
2) "0"
127.0.0.1:6379> LINSERT nums AFTER 7 3
(integer) 3
127.0.0.1:6379> LRANGE nums 0 -1
1) "7"
2) "3"
3) "0"
127.0.0.1:6379> LINSERT nums BEFORE 3 1
(integer) 4
127.0.0.1:6379> LRANGE nums 0 -1
1) "7"
2) "1"
3) "3"
4) "0"

集合类型

集合类型中每个元素都是不同的,且没有顺序。一个集合类型(set)键可以存储至多 2³²-1 个字符串。

集合类型和列表类型有相似之处,我们通过下表将其进行对比。

集合类型列表类型
存储内容至多 2³²-1 个字符串至多 2³²-1 个字符串
有序性
唯一性

集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合类型在 Redis 内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是 O(1)。最方便地是多个集合类型键之间还可以进行并集、交集和差集运算。

命令

1. 增加/删除元素

SADD key member [member ...]
SREM key member [member ...]

SADD 命令用来向集合中增加一个或多个元素,如果键不存在则会自动创建。因为在一个集合中不能有相同的元素,所以如果要加入的元素已经存在于集合中就会忽略这个元素。该命令的返回值是成功加入的元素数量(忽略的元素不计算在内)。例如:

127.0.0.1:6379> SADD letters a
(integer) 1
127.0.0.1:6379> SADD letters a b c
(integer) 2

第二条 SADD 命令的返回值为 2,是因为元素“a”已经存在,所以实际上只加入了两个元素。

SREM 命令用来从集合中删除一个或多个元素,并返回删除成功的个数,例如:

127.0.0.1:6379> SREM letters c d
(integer) 1

由于元素“d”在集合中不存在,所以只删除了一个元素,返回值为 1。

2. 获得集合中的所有元素

SMEMBERS key

SMEMBERS 命令会返回集合中的所有元素,例如:

127.0.0.1:6379> SMEMBERS letters
1) "a"
2) "b"

3. 判断元素是否在集合中

SISMEMBER key member

判断一个元素是否在集合中是一个时间复杂度为 O(1) 的操作,无论集合中有多少个元素,SISMEMBER 命令始终可以极快地返回结果。当值存在时 SISMEMBER 命名返回 1,当值不存在或键不存在时返回 0,例如:

127.0.0.1:6379> SISMEMBER letters a
(integer) 1
127.0.0.1:6379> SISMEMBER letters d
(integer) 0

4. 集合间运算

SDIFF key [key ...]
SINTER key [key ...]
SUNION key [key ...]

上面这3个命令都是用来进行多个集合间运算的。

(1)SDIFF 命令用来对多个集合执行差集运算。集合 A 与集合 B 的差集表示为 A-B,代表所有属于 A 且不属于 B 的元素构成的集合,即 A-B={x|x∈A且x∉B}。例如:

{1, 2, 3} – {2, 3, 4} = {1}

{2, 3, 4} – {1, 2, 3} = {4}

SDIFF 命令的使用方法如下:

127.0.0.1:6379> SADD setA 1 2 3
(integer) 3
127.0.0.1:6379> SADD setB 2 3 4
(integer) 3
127.0.0.1:6379> SDIFF setA setB
1) "1"
127.0.0.1:6379> SDIFF setB setA
1) "4"

SDIFF 命令支持同时传入多个键,例如:

127.0.0.1:6379> SADD setC 2 3
(integer) 2
127.0.0.1:6379> SDIFF setA setB setC
1) "1"

计算顺序是先计算 setA – setB,再计算结果与 setC 的差集。

(2)SINTER 命令用来对多个集合执行交集运算。集合 A 与集合 B 的交集表示为 A∩B,代表所有属于 A 且属于 B 的元素构成的集合,即 A∩B={x|x∈A且x∈B}。例如:

{1, 2, 3} ∩ {2, 3, 4} = {2, 3}

SINTER 命令的使用方法如下:

127.0.0.1:6379> SINTER setA setB
1) "2"
2) "3"

SINTER 命令同样支持同时传入多个键,如:

127.0.0.1:6379> SINTER setA setB setC
1) "2"
2) "3"

(3)SUNION 命令用来对多个集合执行并集运算。集合 A 和集合 B 的并集表示为 A∪B,代表所有属于 A 或属于 B 的元素构成的集合,即 A∪B={x|x∈A或x∈B}。例如:

{1, 2, 3} ∪ {2, 3, 4} = {1, 2, 3, 4}

SUNION 命令的使用方法如下:

127.0.0.1:6379> SUNION setA setB
1) "1"
2) "2"
3) "3"
4) "4"

SUNION 命令同样支持同时传入多个键,例如:

127.0.0.1:6379> SUNION setA setB setC
1) "1"
2) "2"
3) "3"
4) "4"

5. 获得集合中元素个数

SCARD key

SCARD 命令用来获得集合中的元素个数,例如:

127.0.0.1:6379> SMEMBERS letters
1) "a"
2) "b"
127.0.0.1:6379> SCARD letters
(integer) 2

6. 随机获得集合中的元素

SRANDMEMBER key [count]

SRANDMEMBER 命令用来随机从集合中获取一个元素,如:

127.0.0.1:6379> SMEMBERS letters
1) "a"
2) "b"
127.0.0.1:6379> SRANDMEMBER letters
"b"
127.0.0.1:6379> SRANDMEMBER letters
"b"
127.0.0.1:6379> SRANDMEMBER letters
"a"

还可以传递 count 参数来一次随机获得多个元素,根据 count 的正负不同,具体表现也不同。

(1)当 count 为正数时,SRANDMEMBER 会随机从集合里获得 count 个不重复的元素。如果 count 值大于集合中的元素个数,则 SRANDMEMBER 会返回集合中的全部元素。

(2)当 count 为负数时,SRANDMEMBER 会随机从集合里获得 |count| 个的元素,这些元素有可能相同。

作为示例,我们现在 letters 集合中加入两个元素:

127.0.0.1:6379> SADD letters c d
(integer) 2

现在 letters 集合中共有“a”、“b”、“c”、“d” 4 个元素,下面使用不同的参数对 SRANDMEMBER 命令进行测试:

127.0.0.1:6379> SRANDMEMBER letters 2
1) "a"
2) "c"
127.0.0.1:6379> SRANDMEMBER letters 2
1) "a"
2) "b"
127.0.0.1:6379> SRANDMEMBER letters 100
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> SRANDMEMBER letters -2
1) "c"
2) "a"
127.0.0.1:6379> SRANDMEMBER letters -10
 1) "c"
 2) "c"
 3) "b"
 4) "b"
 5) "a"
 6) "d"
 7) "a"
 8) "d"
 9) "d"
10) "a"

7. 从集合中弹出一个元素

SPOP key

我们在集合类型中使用过 LPOP 命令,作用是从列表左边弹出一个元素(即返回元素的值并删除它)。SPOP 命令的作用与之类似,但由于集合类型的元素是无序的,所以 SPOP 命令会从集合中随机选择一个元素弹出。例如:

127.0.0.1:6379> SPOP letters
"a"
127.0.0.1:6379> SMEMBERS letters
1) "b"
2) "c"
3) "d"

有序集合类型

有序集合类型(sorted set)的特点从它的名字就可以看出,它与集合类型的区别就是“有序”二字。

在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能够获得分数最高(或最低)的前 N 个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是它们的分数却可以相同。

有序集合类型在某些方面和列表类型有些相似。

(1)二者都是有序的。

(2)二者都可以获得某一范围的元素。

但是二者有着很大的区别,这使得它们的应用场景也是不同的。

(1)列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度回变慢,所以它更适合实现如“最新新闻”或“日志”这样很少访问中间元素的应用。

(2)有序集合类型是使用散列表和跳跃表(Skip list)实现的,所以即使读取位于中间部分的数据速度也很快(时间复杂度是 O(log(N)))。

(3)列表中不能简单地调整某个元素的位置,但是有序集合可以(通过更改这个元素的分数)。

(4)有序集合要比列表类型更耗费内存。

命令

1. 增加元素

ZADD key score member [score member ...]

ZADD 命令用来向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。ZADD 命令的返回值是新加入到集合中的元素个数(不包含之前已经存在的元素)。

假设我们用有序集合模拟学生成绩,现在要记录 A、B和C 三名同学的分数(分别是89分、67分、100分):

127.0.0.1:6379> ZADD grades 89 A 67 B 100 C
(integer) 3

这时我们发现 B 同学的分数录入有误,实际的分数应该是76分,可以用 ZADD 命令修改 B 同学的分数:

127.0.0.1:6379> ZADD grades 76 B
(integer) 0

分数不仅可以是整数,还支持双精度浮点数:

127.0.0.1:6379> ZADD testboard 17E+307 a
(integer) 1
127.0.0.1:6379> ZADD testboard 1.5 b
(integer) 1
127.0.0.1:6379> ZADD testboard +inf c
(integer) 1
127.0.0.1:6379> ZADD testboard -inf d
(integer) 1

其中 +inf 和 -inf 分别表示正无穷和负无穷。

2. 获得元素的分数

ZSCORE key member

示例如下:

127.0.0.1:6379> ZSCORE grades A
"89"

3. 获得排名在某个范围的元素列表

ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]

ZRANGE 命令会按照元素分数从小到大的顺序返回索引从 start 到 stop 之间的所有元素(包含两端的元素)。ZRANGE 命令与 LRANGE 命令十分相似,如索引都是从 0 开始,负数代表从后向前查找(-1 表示最后一个元素)。就像这样:

127.0.0.1:6379> ZRANGE grades 0 2
1) "B"
2) "A"
3) "C"
127.0.0.1:6379> ZRANGE grades 1 -1
1) "A"
2) "C"

如果需要同时获得元素的分数的话可以在 ZRANGE 命令的末尾加上 WITHSCORES 参数,这时返回的数据格式就从“元素1,元素2,…,元素n”变成了“元素1,分数1,元素2,分数2,…,元素n,分数n”,例如:

127.0.0.1:6379> ZRANGE grades 0 -1 WITHSCORES
1) "B"
2) "76"
3) "A"
4) "89"
5) "C"
6) "100"

ZRANGE 命令的时间复杂度为 O(log n+m)(其中 n 为有序集合的基数,m 为返回的元素个数)。

如果两个元素的分数相同,Redis 会按照字典顺序(即 “0” < “9” < “A” < “Z” < “a” < “z” 这样的顺序)来进行排列。

ZREVARANGE 命令和 ZRANGE 的唯一不同在于 ZREVRANGE 命令是按照元素分数从大到小的顺序给出结果的。

4. 获得指定分数范围的元素

ZRANGEBYSOCRE key min max [WITHSCORES] [LIMIT offset count]

ZRANGEBYSOCRE 命令参数虽然多,但是不难理解。该命令按照元素分数从小到大的顺序返回分数在 min 和 max 之间(包含 min 和 max)的元素:

127.0.0.1:6379> ZRANGEBYSCORE grades 80 100
1) "A"
2) "C"

如果希望分数范围不包含端点值,可以在分数前加上 “(” 符号。例如,希望返回“80分到100分的数据,可以包含80分,但不包含100分”。我们对上面的命令稍作修改:

127.0.0.1:6379> ZRANGEBYSCORE grades 80 (100
1) "A"

min 和 max 还支持无穷大,同 ZADD 命令一样,-inf 和 +inf 分别表示负无穷和正无穷。比如你希望得到所有分数高于80分(不包含80分)的人的名单,但你却不知道最高分是多少(虽然这一般不可能),这时就可以用上 +inf 了:

127.0.0.1:6379> ZRANGEBYSCORE grades (80 +inf
1) "A"
2) "C"

WITHSCORES 参数的用法与 ZRANGE 命令是一样的,这里就不再进行赘述。

了解 SQL 语句的同学对 LIMIT offset count 应该很熟悉,在本命令中 LIMIT offset count 与 SQL 中的用法基本相同,即在获得的元素列表的基础上向后偏移 offset 个元素,并且值获取前 count 元素。为了方便演示,我们再向 grades 键中加些元素:

127.0.0.1:6379> ZADD grades 56 D 92 E 67 F
(integer) 3

现在 grades 键中的所有元素为:

127.0.0.1:6379> ZRANGE grades 0 -1 WITHSCORES
 1) "D"
 2) "56"
 3) "F"
 4) "67"
 5) "B"
 6) "76"
 7) "A"
 8) "89"
 9) "E"
10) "92"
11) "C"
12) "100"

想获得分数高于60分的从第二个人开始的3个人:

127.0.0.1:6379> ZRANGEBYSCORE grades 60 +inf LIMIT 1 3
1) "B"
2) "A"
3) "E"

那么,如果想获取分数低于或等于100分的前3个人应该怎么办呢?这时可以使用 ZREVRANGEBYSCORE 命令来进行实现。对照前文介绍过的 ZRANGE 命令和 ZREVRANGE 命令之间的关系,相信你应该很容易就能明白 ZREVRANGEBYSCORE 命令的功能。需要注意的是 ZREVRANGEBYSCORE 命令不仅是按照元素分数从大到小的顺序给出结果的,而且它的 min 和 max 参数的顺序和 ZRANGEBYSCORE 命令是相反的。就像这样:

127.0.0.1:6379> ZREVRANGEBYSCORE grades 100 0 LIMIT 0 3
1) "C"
2) "E"
3) "A"

5. 增加某个元素的分数

ZINCRBY key increment member

ZINCRBY 命令可以增加一个元素的分数,返回值是更改后的分数。例如,想给B同学增加4分:

127.0.0.1:6379> ZINCRBY grades 4 B
"80"

increment 也可以是个负数表示减分,例如,给B同学减4分:

127.0.0.1:6379> ZINCRBY grades -4 B
"76"

如果指定的元素不存在,Redis 在执行命令前会先建立它并将它的分数赋为 0 再执行操作。

6. 获得集合中元素的数量

ZCARD key

例如:

127.0.0.1:6379> ZCARD grades
(integer) 6

7. 获得指定分数范围内的元素个数

ZCOUNT key min max

例如:

127.0.0.1:6379> ZCOUNT grades 90 100
(integer) 2

ZCOUNT 命令的 min 和 max 参数的特性与 ZRANGEBYSCORE 命令中的一样:

127.0.0.1:6379> ZCOUNT grades (89 +inf
(integer) 2

8. 删除一个或多个元素

ZREM key member [member ...]

ZREM 命令的返回值是成功删除的元素数量(不包含本来就不存在的元素)。

127.0.0.1:6379> ZREM grades C
(integer) 1
127.0.0.1:6379> ZCARD grades
(integer) 5

9. 按照排名范围删除元素

ZREMRANGEBYRANK key start stop

ZREMRANGEBYRANK 命令按照元素分数从小到大的顺序(即索引 0 表示最小的值)删除处在指定排名范围内的所有元素,并返回删除的元素数量。如:

127.0.0.1:6379> ZADD testRem 1 a 2 b 3 c 4 d 5 e 6 f
(integer) 6
127.0.0.1:6379> ZREMRANGEBYRANK testRem 0 2
(integer) 3
127.0.0.1:6379> ZRANGE testRem 0 -1
1) "d"
2) "e"
3) "f"

10. 按照分数范围删除元素

ZREMRANGEBYSCORE key min max

ZREMRANGEBYSCORE 命令会删除指定分数范围内的所有元素,参数 min 和 max 的特性和 ZRANGEBYSCORE 命令中的一样。返回值是删除的元素数量。如:

127.0.0.1:6379> ZREMRANGEBYSCORE testRem (4 5
(integer) 1
127.0.0.1:6379> ZRANGE testRem 0 -1
1) "d"
2) "f"

11. 获得元素的排名

ZRANK key member
ZREVRANK key member

ZRANK 命令会按照元素分数从小到大的顺序获得指定的元素的排名(从 0 开始,即分数最小的元素排名为 0)。如:

127.0.0.1:6379> ZRANK grades A
(integer) 3

ZREVRANK 命令则相反(分数最大的元素排名为 0):

127.0.0.1:6379> ZREVRANK grades A
(integer) 1

关于本文内容的参考来自《Redis入门指南》一书。

欢迎关注我的公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值