第二章 Redis API的使用 单线程介绍

栏目: 数据库 · 发布时间: 7年前

内容简介:Redis入门教程目录:通过这部分让大家对Redis的五种数据结构有初步的认识,对于Redis来说,每一种数据结构都有着自己的内部编码,而且是多种实现的,这样Redis会在合适的场景选择合适的内部编码,通过这样做的好处:
第二章 Redis API的使用 单线程介绍

Redis入门教程目录: 【Redis入门教程目录】

数据结构和内部编码

通过这部分让大家对 Redis 的五种数据结构有初步的认识,对于Redis来说,每一种数据结构都有着自己的内部编码,而且是多种实现的,这样Redis会在合适的场景选择合适的内部编码,通过 OBJECT ENCODING [key] 可以参看指定 key 的内部编码。

这样做的好处:

a. 改进内部编码,对外的数据结构和命令没有影响,对用户提供黑箱模型。

b. 多种内部编码可在不同场景下发挥各自的优势。如: ziplist 比较节约内存,但是元素比较多的时候,性能会有所下降,此时Redis会将编码自动转换为 linkedlist ,性能会有所改善。

第二章 Redis API的使用 单线程介绍

单线程

了解Redis的单线程架构,有助于大家对Redis的进一步学习和排解问题。

第二章 Redis API的使用 单线程介绍

Redis处理网络请时候的求单线程可以抽象成这样,通向Redis的路只有一条,且这条路是个单车道,只容的下一辆车同时使用,而我们使用的Redis命令即为这些车辆,当我们执行多个命令的时候,只有等第一个命令执行完成了后面的命令才会执行,否则会一直处于等待状态。

第二章 Redis API的使用 单线程介绍

Redis单线程的架构需要我们注意几点

a. 一次只运行一条命令

b. 拒绝长(慢)命令(keys、flushall、flushdb、slow lua script、mutil/exec、operate、big value)

至于为什么单线程还这么快,这里有个原因,Redis客户端的到Redis服务器的网络请求采用了 多路I/O复用模型(非阻塞I/O) ,利用 select 、 poll 、 epoll 可以 同时监听多个流的I/O(客户端到服务器的网络请求)事件的能力 ,在空闲的时候,会把当前线程阻塞掉,当有一个或者多个流有 I/O 事件时,就从阻塞态中唤醒, 轮训一遍所有的流 并且依次处理就绪的流。这样就算出现有的流的 I/O 因为网络原因很慢,也不会影响别的流的 I/O (非阻塞),因为是轮训所有的流的 I/O 。这里的“多路”指的是多个网络连接,“复用”指的是复用同一个线程。 第二章 Redis API的使用 单线程介绍

通用命令

Redis一些通用命令,比如删除一个键、计算数据库的大小、设置键的过期时间等,这些命令有很多,这里主要介绍 7 个,完整的命令大家可以参考官方文档。

  1. KEYS [pattern]

    时间复杂度为 O(N) , N 为数据库中 Key 的数量。 这个命令由于时间复杂度为O(N)所以一般生产环境不使用,如果需要遍历全部数据,可以使用Scan命令,时间复杂度为O(1)。 查找所有符合给定模式 pattern 的 key ,比如说:

  • KEYS * 匹配数据库中所有的 key 。
  • KEYS h?llo 匹配 hello 、 hallo 等 key 。
  • KEYS h*llo 匹配 hllo 和 haaaaaallo 等 key 。
  • KEYS h[abe]llo 匹配 hallo 、 hbllo 和 hello 。
    返回值: 符合给定模式的 key 列表。
  1. DBSIZE

    时间复杂度为 O(1) ,计算的时候不是扫描整个表,因为Redis有个计数器,实时更新Key总数。

    查找返回当前数据库的 key 的数量。

    返回值:返回当前数据库的 key 的数量。

    代码演示:

redis> DBSIZE
(integer) 5

redis> SET new_key "hello_moto"     # 增加一个 key 试试
OK

redis> DBSIZE
(integer) 6
复制代码
  1. EXISTS key

    时间复杂度为 O(1) 。

    检查给定 key 是否存在。

    返回值:若 key 存在,返回 1 ,不存在返回 0 。

  2. DEL key [key ...]

    时间复杂度为 O(N) , N 为被删除的 key 的数量,其中删除单个字符串类型的 key ,时间复杂度为 O(1) ;删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为 O(M) , M 为以上数据结构内的元素数量。

    删除指定的一个或者多个 key ,不存在的 key 会被忽略。 返回值: 被删除的 key 的数量。

  3. EXPIRE key seconds

    时间复杂度为 O(1) 。

    为给定的 key 设置生存时间,当 key 过期时,它会被自动 删除 。

    返回值:设置成功返回 1 ,当 key 不存在或者设置失败的时候返回 0 。

  4. PERSIST key

    时间复杂度为 O(1) 。

    移除给定 key 的生存时间,将这个 key 转换成持久的。

    返回值:当生存时间移除成功时,返回 1 ,如果 key 不存在或者没有设置生存时间,返回 0 。

    代码演示:

redis> SET mykey "Hello"
OK

redis> EXPIRE mykey 10  # 为 key 设置生存时间
(integer) 1

redis> TTL mykey
(integer) 10

redis> PERSIST mykey    # 移除 key 的生存时间
(integer) 1

redis> TTL mykey
(integer) -1
复制代码
  1. TTL key

    时间复杂度 O(1) 。

    以秒为单位,返回给定 key 的剩余生存时间(TTL,time to live)。

    返回值:当 key 不存在时,返回 -2 ,当 key 存在但是没有设置生存时间时,返回 -1 ,否则返回 key 的剩余生存时间。

    代码演示:

# 不存在的 key

redis> FLUSHDB
OK

redis> TTL key
(integer) -2


# key 存在,但没有设置剩余生存时间

redis> SET key value
OK

redis> TTL key
(integer) -1


# 有剩余生存时间的 key

redis> EXPIRE key 10086
(integer) 1

redis> TTL key
(integer) 10084
复制代码

五种数据结构

这里介绍Redis的五种数据结构String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Zset(即Sorted Set有序集合)的结构和一些命令。

字符串

字符串是Redis中最基础的数据结构。

键值结构

字符串的值虽然是字符串但是可以保存很多种类型的数据,如:简单的字符串、JSON、XML、数字、二进制等。需要注意一点的是,Redis中字符串类型的值最大能保存512MB。

第二章 Redis API的使用 单线程介绍

命令

  1. SET key value [EX seconds] [PX milliseconds] [NX|XX] 时间复杂度 O(1) 。

    将字符串值 value 关联到 key ,如果 key 已经持有其他值, SET 就覆写旧值,无视类型,当 SET 命令对一个带有生存时间(TTL)的键进行设置之后,该键原有的TTL将被清除。

    可选参数:

  • EX seconds :将键的过期时间设置为 seconds 秒。 执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value 。
  • PX milliseconds :将键的过期时间设置为 milliseconds 毫秒。执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value 。
  • NX :只在键不存在时,才对键进行设置操作。执行 SET key value NX 的效果等同于执行 SETNX key value 。
  • XX :只在键已经存在时,才对键进行设置操作。

因为 SET 命令可以通过参数来实现 SETNX 、 SETEX 以及 PSETEX 命令的效果,所以 Redis 将来的版本可能会移除并废弃 SETNX 、 SETEX 和 PSETEX 这三个命令。

返回值:在Redis 2.6.12版本以前, SET 命令总是返回 OK 。

从Redis 2.6.12版本开始, SET 命令只在设置操作成功完成时才返回 OK ;如果命令使用了 NX 或者 XX 选项, 但是因为条件没达到而造成设置操作未执行, 那么命令将返回空批量回复(NULL Bulk Reply)。 代码演示:

# 使用 EX 选项
redis> SET key-with-expire-time "hello" EX 10086
OK

redis> GET key-with-expire-time
"hello"

redis> TTL key-with-expire-time
(integer) 10069
复制代码
  1. GET key 时间复杂度 O(1) 。

    获取与键 key 相关联的字符串值。

    返回值:如果键 key 不存在,那么返回特殊值 nil ;否则,返回键 key 的值。

    如果键 key 的值并非字符串类型,那么返回一个错误,因为 GET 命令只能用于字符串值。

    代码演示:

redis> GET db
(nil)

redis> SET db redis
OK

redis> GET db
"redis"
复制代码
  1. DEL key [key ...] 时间复杂度为 O(N) , N 为被删除的 key 的数量,其中删除单个字符串类型的 key ,时间复杂度为 O(1) ;删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为 O(M) , M 为以上数据结构内的元素数量。

    删除指定的一个或者多个 key ,不存在的 key 会被忽略。 返回值: 被删除的 key 的数量。

    代码演示:

# 同时删除多个 key

redis> SET name "redis"
OK

redis> SET type "key-value store"
OK

redis> SET website "redis.com"
OK

redis> DEL name type website
(integer) 3
复制代码
  1. MSET key value [key value ...] 时间复杂度 O(N) ,其中 N 为被设置的键数量。

    同时为多个键设置值。如果某个给定键已经存在,那么 MSET 将使用新值去覆盖旧值,如果这不是你所希望的效果,请考虑使用 MSETNX 命令,这个命令只会在所有给定键都不存在的情况下进行设置。 MSET 是一个 原子性(atomic) 操作,所有给定键都会在同一时间内被设置,不会出现某些键被设置了但是另一些键没有被设置的情况。

    返回值: MSET 命令总是返回 OK 。

    代码演示:

redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny"
OK

redis> MGET date time weather
1) "2012.3.30"
2) "11:00 a.m."
3) "sunny"
复制代码
  1. MSETNX key value [key value ...] 时间复杂度 O(N) ,其中 N 为被设置的键数量。

    当且仅当所有给定键都** 不存在 时,为所有给定键设置值。即使只有一个给定键已经存在, MSETNX 命令也会拒绝执行对所有键的设置操作。 MSETNX 是一个 原子性(atomic) 操作,所有给定键要么就全部都被设置,要么就全部都不设置,不可能出现第三种状态。 返回值: 当所有给定键都设置成功时,命令返回 1 ;如果因为某个给定键已经存在而导致设置未能成功执行,那么命令返回 0 。

    代码演示:

redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis"
(integer) 1

redis> MGET rmdbs nosql key-value-store
1) "MySQL"
2) "MongoDB"
3) "redis"
复制代码
  1. MGET key [key ...] 时间复杂度 O(N) ,其中 N 为给定键的数量。

    返回给定的一个或多个字符串键的值。如果给定的字符串键里面,有某个键不存在,那么这个键的值将以特殊值 nil 表示。 返回值: MGET 命令将返回一个列表,列表中包含了所有给定键的值。

    代码演示:

redis> SET redis redis.com
OK

redis> SET mongodb mongodb.org
OK

redis> MGET redis mongodb
1) "redis.com"
2) "mongodb.org"

redis> MGET redis mongodb mysql     # 不存在的  mysql  返回 nil
1) "redis.com"
2) "mongodb.org"
3) (nil)
复制代码
  1. N次GET和一次MGET对比 总所周知,Redis采用的是客户端-服务器方式,即在一次round trip中,客户端发送一条命令,服务器解析命令并执行,然后向客户端返回结果,如果执行 N 条命令,就是 N 个请求 N 次执行 N 个返回

    第二章 Redis API的使用 单线程介绍
    如果我们把 N 条命令都放在一个请求中,一次请求多个执行一个返回,那么就可以大大的降低网络时间的开销,这个也就是Redis的pipline
    第二章 Redis API的使用 单线程介绍
  2. N次SET和一次MSET对比 同7

哈希

Redis的哈希是键值对的集合,是字符串字段和字符串值之间的映射。

键值结构

Hash 数据结构即数据存储为 field 、 value 的格式存储

第二章 Redis API的使用 单线程介绍
可以将 field 、 value

看成一对键值对结构

第二章 Redis API的使用 单线程介绍

命令

  1. HSET key field value

    时间复杂度 O(1) 。

    将哈希表 key 中域 field 的值设置为 value ,如果给定的哈希表不存在,那么一个新的哈希表将被创建并执行 HSET 操作,如果域 field 已存在于哈希表中,那么它的旧值将被新值 value 覆盖。

    返回值:当 HSET 命令在哈希表中新创建 field 域并成功为它设置值时,命令返回 1 ;如果域 field 已经存在于哈希表,并且 HSET 命令成功使用新值覆盖了它的旧值,那么命令返回 0 。

    代码演示:

redis> HSET website google "www.g.cn"
(integer) 1

redis> HGET website google
"www.g.cn"
复制代码
  1. HGET key field

    时间复杂度 O(1) 。

    返回哈希表中给定域的值。

    返回值: HGET 命令在默认情况下返回给定域的值,如果给定域不存在于哈希表中,又或者给定的哈希表并不存在,那么命令返回 nil 。 代码演示:

redis> HSET homepage redis redis.com
(integer) 1

redis> HGET homepage redis
"redis.com"
复制代码
  1. HGETALL key

    时间复杂度 O(N) , N 为哈希表的大小,谨慎用。

    返回哈希表的所有的域和值,在返回值里,紧跟每个域(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。

    返回值:以列表形式返回哈希表的域和域的值,若 key 不存在,返回空列表。 代码演示:

redis> HSET people jack "Jack Sparrow"
(integer) 1

redis> HSET people gump "Forrest Gump"
(integer) 1

redis> HGETALL people
1) "jack"          # 域
2) "Jack Sparrow"  # 值
3) "gump"
4) "Forrest Gump"
复制代码
  1. HDEL key field [field ...]

    时间复杂度 O(N) , N 为要删除的域的数量。

    删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。

    返回值:被成功移除的域的数量,不包括被忽略的域。

    代码演示:

# 测试数据

redis> HGETALL abbr
1) "a"
2) "apple"
3) "b"
4) "banana"
5) "c"
6) "cat"
7) "d"
8) "dog"


# 删除单个域

redis> HDEL abbr a
(integer) 1


# 删除不存在的域

redis> HDEL abbr not-exists-field
(integer) 0


# 删除多个域

redis> HDEL abbr b c
(integer) 2

redis> HGETALL abbr
1) "d"
2) "dog"
复制代码
  1. HMSET key field value [field value ...]

    时间复杂度 O(N) , N 为 field-value 对的数量。

    同时将多个 field-value (域-值)对设置到哈希表 key 中,此命令会覆盖哈希表中已存在的域,如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。

    返回值:如果命令执行成功,返回 OK ,当 key 不是哈希表(hash)类型时,返回一个错误。 代码演示:

redis> HMSET website google www.google.com yahoo www.yahoo.com
OK

redis> HGET website google
"www.google.com"

redis> HGET website yahoo
"www.yahoo.com"
复制代码
  1. HMGET key field [field ...]

    时间复杂度 O(N) , N 为给定域的数量。

    返回哈希表 key 中,一个或多个给定域的值,如果给定的域不存在于哈希表,那么返回一个 nil 值,因为不存在的 key 被当作一个空哈希表来处理,所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。

    返回值:一个包含多个给定域的关联值的表,表值的排列顺序和给定域参数的请求顺序一样。

    代码演示:

redis> HMSET pet dog "doudou" cat "nounou"    # 一次设置多个域
OK

redis> HMGET pet dog cat fake_pet             # 返回值的顺序和传入参数的顺序一样
1) "doudou"
2) "nounou"
3) (nil)                                      # 不存在的域返回nil值
复制代码
  1. N次HGET和一次HMGET对比

    参考字符串的 N 次 GET 和一次 MGET 对比,大概相同

列表

列表用于储存多个有序的字符串,列表是一种比较灵活的数据结构,可以充当 栈 和 队列 的角色。

键值结构

列表的 value 其实是一个双向链表,可以在链表的两头插入或者删除元素

第二章 Redis API的使用 单线程介绍

命令

  1. LPUSH key value [value ...]

    时间复杂度 O(1) 。

    将一个或多个值 value 插入到列表 key 的表头,如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头:比如说,对空列表 mylist 执行命令 LPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 LPUSH mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令,如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作,当 key 存在但不是列表类型时,返回一个错误。

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

# 加入单个元素

redis> LPUSH languages python
(integer) 1


# 加入重复元素

redis> LPUSH languages python
(integer) 2

redis> LRANGE languages 0 -1     # 列表允许重复元素
1) "python"
2) "python"


# 加入多个元素

redis> LPUSH mylist a b c
(integer) 3

redis> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "a"
复制代码
  1. RPUSH key value [value ...]

    时间复杂度 O(1) 。

    将一个或多个值 value 插入到列表 key 的表尾(最右边),如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如说,对空列表 mylist 执行命令 RPUSH mylist a b c ,列表的值将是 c b a ,这等同于原子性地执行 RPUSH mylist a 、 RPUSH mylist b 和 RPUSH mylist c 三个命令,如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作,当 key 存在但不是列表类型时,返回一个错误。

    返回值:执行 RPUSH 命令后,列表的长度。 代码演示:

# 添加单个元素

redis> RPUSH languages c
(integer) 1


# 添加重复元素

redis> RPUSH languages c
(integer) 2

redis> LRANGE languages 0 -1 # 列表允许重复元素
1) "c"
2) "c"


# 添加多个元素

redis> RPUSH mylist a b c
(integer) 3

redis> LRANGE mylist 0 -1
1) "a"
2) "b"
3) "c"
复制代码
  1. LPOP key

    时间复杂度 O(1) 。

    移除头元素并返回列表 key 新的头元素。

    返回值:列表的头元素。当 key 不存在时,返回 nil 。 代码演示:

# 加入单个元素
redis> LLEN course
(integer) 0

redis> RPUSH course algorithm001
(integer) 1

redis> RPUSH course c++101
(integer) 2

redis> LPOP course  # 移除头元素
"algorithm001"
复制代码
  1. RPOP key

    时间复杂度 O(1) 。

    移除尾元素并返回列表 key 新的尾元素。

    返回值:列表的尾元素。当 key 不存在时,返回 nil 。 代码演示:

redis> RPUSH mylist "one"
(integer) 1

redis> RPUSH mylist "two"
(integer) 2

redis> RPUSH mylist "three"
(integer) 3

redis> RPOP mylist           # 返回被弹出的元素
"three"

redis> LRANGE mylist 0 -1    # 列表剩下的元素
1) "one"
2) "two"
复制代码
  1. LINDEX key index

    时间复杂度 O(N) , N 为到达下标 index 过程中经过的元素数量。因此,对列表的头元素和尾元素执行 LINDEX 命令,复杂度为O(1)。

    返回列表 key 中,下标为 index 的元素,下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推,你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推,如果 key 不是列表类型,返回一个错误。

    返回值:列表中下标为 index 的元素。如果 index 参数的值不在列表的区间范围内(out of range),返回 nil 。

    代码演示:

redis> LPUSH mylist "World"
(integer) 1

redis> LPUSH mylist "Hello"
(integer) 2

redis> LINDEX mylist 0
"Hello"

redis> LINDEX mylist -1
"World"

redis> LINDEX mylist 3        # index不在 mylist 的区间范围内
(nil)
复制代码
  1. LINSERT key BEFORE|AFTER pivot value

    时间复杂度 O(N) , N 为寻找 pivot 过程中经过的元素数量。

    将值 value 插入到列表 key 当中,位于值 pivot 之前或之后,当 pivot 不存在于列表 key 时,不执行任何操作,当 key 不存在时, key 被视为空列表,不执行任何操作,如果 key 不是列表类型,返回一个错误。

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

    代码演示:

redis> RPUSH mylist "Hello"
(integer) 1

redis> RPUSH mylist "World"
(integer) 2

redis> LINSERT mylist BEFORE "World" "There"
(integer) 3

redis> LRANGE mylist 0 -1
1) "Hello"
2) "There"
3) "World"


# 对一个非空列表插入,查找一个不存在的 pivot

redis> LINSERT mylist BEFORE "go" "let's"
(integer) -1                                    # 失败


# 对一个空列表执行 LINSERT 命令

redis> EXISTS fake_list
(integer) 0

redis> LINSERT fake_list BEFORE "nono" "gogogog"
(integer) 0                                      # 失败
复制代码

集合

Redis的 Set 是 String 类型的无序集合,这里的集合也就是我们小学都接触到的集合,可以求交集、并集、差集等。集合成员是唯一的,这就意味着集合中不能出现重复的数据。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

键值结构

左边为 key ,是字符串类型。右边为 value ,可以将一些字符串进行一些组合,是集合类型。Redis中的集合类型还支持集合之间的操作,这与Redis中的其他数据结构是不同的,Redis可以对两个集合进行操作,取两个集合的交集,并集,差集以及对称差集等。

第二章 Redis API的使用 单线程介绍

命令

  1. SADD key member [member …]

    时间复杂度 O(N) , N 为被添加的元素的数量。

    将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略,假如 key 不存在,则创建一个只包含 member 元素作成员的集合,当 key 不是集合类型时,返回一个错误。

    返回值:被添加到集合中的新元素的数量,不包括被忽略的元素。

    代码演示:

# 添加单个元素

redis> SADD bbs "discuz.net"
(integer) 1


# 添加重复元素

redis> SADD bbs "discuz.net"
(integer) 0


# 添加多个元素

redis> SADD bbs "tianya.cn" "groups.google.com"
(integer) 2

redis> SMEMBERS bbs
1) "discuz.net"
2) "groups.google.com"
3) "tianya.cn"
复制代码
  1. SPOP key [count]

    时间复杂度 O(1) 。

    随机移除 count 个元素并返回被移除的元素。

    返回值:被移除的随机元素。当 key 不存在或 key 是空集时,返回 nil 。

    代码演示:

redis> SMEMBERS db
1) "MySQL"
2) "MongoDB"
3) "Redis"

redis> SPOP db
"Redis"

redis> SMEMBERS db
1) "MySQL"
2) "MongoDB"

redis> SPOP db
"MySQL"

redis> SMEMBERS db
1) "MongoDB"
复制代码
  1. SREM key member [member …]

    时间复杂度 O(N) , N 为给定 member 元素的个数。

    移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略,当 key 不是集合类型,返回一个错误。

    返回值:被成功移除的元素的个数,不包括被忽略的元素。

    代码演示:

# 测试数据

redis> SMEMBERS languages
1) "c"
2) "lisp"
3) "python"
4) "ruby"


# 移除单个元素

redis> SREM languages ruby
(integer) 1


# 移除不存在元素

redis> SREM languages non-exists-language
(integer) 0


# 移除多个元素

redis> SREM languages lisp python c
(integer) 3

redis> SMEMBERS languages
(empty list or set)
复制代码
  1. SMEMBERS key

    时间复杂度 O(N) , N 为集合的基数。

    返回集合 key 中的所有成员,不存在的 key 被视为空集合。

    返回值:集合中的所有成员。

    代码演示:

# key 不存在或集合为空

redis> EXISTS not_exists_key
(integer) 0

redis> SMEMBERS not_exists_key
(empty list or set)


# 非空集合

redis> SADD language Ruby Python Clojure
(integer) 3

redis> SMEMBERS language
1) "Python"
2) "Ruby"
3) "Clojure"
复制代码

有序集合

Redis有序集合和集合一样也是 String 类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个 double 类型的分数。Redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

键值结构

有序集合的 value 包括 score 和 value 两部分,其中 score 表示分值用来 排序 的

第二章 Redis API的使用 单线程介绍

命令

  1. ZADD key [NX|XX] [CH] [INCR] score member [score member …]

    时间复杂度 O(M*log(N)) , N 是有序集的基数, M 为成功添加的新成员的数量。

    将一个或多个 member 元素及其 score 值加入到有序集 key 当中。如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。 score 值可以是整数值或双精度浮点数。如果 key 不存在,则创建一个空的有序集并执行 ZADD 操作。当 key 存在但不是有序集类型时,返回一个错误。

    Redis 3.0.2 为 ZADD 命令添加了 NX 、 XX 、 CH 、 INCR 四个选项:

  • NX : member 必须不存在,才可以设置成功,用于添加。
  • XX : member 必须存在,才可以设置成功,用于更新。
  • CH :返回此次操作后,有序集合元素和分数发生变化的个数。
  • INCR :对 score 做增加,相当于 ZINCRBY 。 返回值: 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
    代码演示:
redis> ZADD ztest 100  java  99  python  80  go  120 kotlin
(integer) 4
# 查看有序集合内所有元素并且按分数排序
 coderknock> ZRANGE ztest 0 -1 WITHSCORES
1) "go"
2) "80"
3) "python"
4) "99"
5) "java"
6) "100"
7) "kotlin"
8) "120"
# 选项填写在 key 后面,位置不能错误
 redis> ZADD ztest 100 java 99 python 80 go 120 kotlin CH
(error) ERR syntax error
 redis> ZADD CH ztest 100 java 99 python 80 go 120 kotlin
(error) ERR syntax error
# 下面两个语句进行了对比,如果不加 CH 显示的数量不包括更新和已经存在的。
 redis>  ZADD ztest CH 100 java 99 python 80 go 121 kotlin
(integer) 1
 redis>  ZADD ztest 100 java 99 python 80 go 120 kotlin
(integer) 0
复制代码
  1. ZREM key member [member …]

    时间复杂度 O(M*log(N)) , N 是有序集的基数, M 为成功移除的成员的数量。

    移除有序集 key 中的一个或多个成员,不存在的成员将被忽略,当 key 存在但不是有序集类型时,返回一个错误。

    返回值:被成功移除的成员的数量,不包括被忽略的成员。

    代码演示:

# 测试数据

redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"
5) "google.com"
6) "10"


# 移除单个元素

redis> ZREM page_rank google.com
(integer) 1

redis> ZRANGE page_rank 0 -1 WITHSCORES
1) "bing.com"
2) "8"
3) "baidu.com"
4) "9"


# 移除多个元素

redis> ZREM page_rank baidu.com bing.com
(integer) 2

redis> ZRANGE page_rank 0 -1 WITHSCORES
(empty list or set)


# 移除不存在元素

redis> ZREM page_rank non-exists-element
(integer) 0
复制代码

以上所述就是小编给大家介绍的《第二章 Redis API的使用 单线程介绍》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

阿里巴巴Java开发手册

阿里巴巴Java开发手册

杨冠宝 / 电子工业出版社 / 2018-1 / 35

《阿里巴巴Java开发手册》的愿景是码出高效,码出质量。它结合作者的开发经验和架构历程,提炼阿里巴巴集团技术团队的集体编程经验和软件设计智慧,浓缩成为立体的编程规范和最佳实践。众所周知,现代软件行业的高速发展对开发者的综合素质要求越来越高,因为不仅是编程相关的知识点,其他维度的知识点也会影响软件的最终交付质量,比如,数据库的表结构和索引设计缺陷可能带来软件的架构缺陷或性能风险;单元测试的失位导致集......一起来看看 《阿里巴巴Java开发手册》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具