目录
一、安装Redis
在MAC环境。
简单的Docker安装Redis见:安装Redis。
二、Redis线程与高性能
2.1 Redis是单线程么?
Redis是单线程主要体现在Redis的网络IO和键值对的读写是由一个线程来完成的。但实际Redis并不是单线程,如持久化、数据过期删除和数据同步等是由其它线程来完成的,即Redis是有多个线程的。
2.2 Redis读写是单线程为何这么快?
- 数据存储在内在中,所有运算都在内行中完成
- 单线程也避免了多线程切换造成的资源损耗(注:因为是单线程,生产环境对Redis的操作是有严格要求的)
2.3 Redis如何处理并发操作命令?
Redis的IO多路复用:redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到 文件事件分派器,事件分派器将事件分发给事件处理器。如下图所示:
redis默认的最大连接数为10000,用如下命令查看:
127.0.0.1:6379> config get maxclients
1) "maxclients"
2) "10000"
127.0.0.1:6379>
查看所有配置项可用命令config get *:
*****************% docker exec -it redis redis-cli
127.0.0.1:6379> CONFIG GET *
1) "rdbchecksum"
2) "yes"
3) "daemonize"
4) "no"
5) "io-threads-do-reads"
6) "no"
7) "lua-replicate-commands"
8) "yes"
9) "always-show-logo"
10) "no"
11) "protected-mode"
12) "no"
13) "rdbcompression"
14) "yes"
15) "rdb-del-sync-files"
16) "no"
17) "activerehashing"
18) "yes"
...
更多配置项详见redis.conf和修改redis的配置项信息。
三、核心数据结构实战
3.1 字符串常用操作实战
SET 存入键值对
SET key value [EX seconds | PX milliseconds | EXAT timestamp | PXAT milliseconds-timestamp | KEEPTTL ] [NX|XX]
添加字符串键值对。
- 如果 key 已经持有其他值, set 就覆写旧值,无视类型。
- 对于某个原本带有生存时间(TTL)的键来说, 当 set 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。
可选参数。
- EX seconds: 设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value
- PX milliseconds: 设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value
- EXAT timestamp:指定过期时间为Unix时间,单位是秒
- PXAT milliseconds-timestamp:指定过期时间为Unix时间,单位是毫秒
- KEETTTL:保存ttl时间
- NX: 只在键不存在时,才对键进行设置操作,常用于添加。 SET key value NX 效果等同于 SETNX key value
- XX: 只在键已经存在时,才对键进行设置操作,常用于更新
127.0.0.1:6379> set time '2023-09-14'
OK
127.0.0.1:6379> get time
"2023-09-14"
# 设置过期时间EX 5 单位是秒
127.0.0.1:6379> set time '2023-09-14' EX 5
OK
127.0.0.1:6379> get time
"2023-09-14"
# 过5秒之后time已过期,获取不到
127.0.0.1:6379> get time
(nil)
# 设置过期时间PX 5000 单位是毫秒
127.0.0.1:6379> set time '2023-09-14' PX 5000
OK
127.0.0.1:6379> get time
"2023-09-14"
# 过5000毫秒之后time已过期,获取不到
127.0.0.1:6379> get time
(nil)
127.0.0.1:6379> set time '2023-09-14' NX
OK
# NX:key为time已存在,设置失败
127.0.0.1:6379> set time '2023-09-14' NX
(nil)
# XX:key为time已存在,设置成功
127.0.0.1:6379> set time '2023-09-14' XX
OK
# XX:key为time1不存在,设置失败
127.0.0.1:6379> set time1 '2023-09-14' XX
(nil)
时间复杂度为O(1)。
返回值:
- 成功时才返回OK。
SETNX
SETNX key value(set if not exists的简写)
将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> setnx name zhangsan
(integer) 0
127.0.0.1:6379> set name zhangxan nx
(nil)
127.0.0.1:6379> get name
"lisi"
时间复杂度为O(1)。
返回值:
- 成功返回OK。
- 否则返回0。
SETEX
SETEX key seconds value
将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在, SETEX 命令将覆写旧值。
该命令相当于以下两条命令 set key value; expire key seconds; 两条命令。
SET key value
EXPIRE key seconds # 设置生存时间
不同的是,SETEX是一个原子操作。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> setex name 10 xxian
OK
127.0.0.1:6379> get name
"xxian"
127.0.0.1:6379> get name
(nil)
时间复杂度为O(1)。
返回值:
- 成功返回OK。
- seconds不合法时,报错ERR value is not an integer or out of range。
MSET 批量存入键值对
MSET key value [key value ...]
批量存储字符串键值对(同时设置一个或多个 key-value 对),如果某个给定 key 已经存在,那么mset会用新值覆盖原来的旧值。
127.0.0.1:6379> mset name 'xxjava' age 25 address '贵州'
OK
127.0.0.1:6379> mget name age address
1) "xxjava"
2) "25"
3) "\xe8\xb4\xb5\xe5\xb7\x9e"
注:mset 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。
时间复杂度为O(N), N 为要设置的 key 数量。
返回值:
- MSET 不可能失败,所以总是返回OK。
MSETNX
MSETNX key value [key value ...]
同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作。(MSETNX是原子性)
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> msetnx a 1 b 2 c 3 d 4
(integer) 1
127.0.0.1:6379> mget a b c d
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> msetnx a 1 e 5 f 6 g 7
(integer) 0
# 不成功是因为key为a 的已经厦
时间复杂度O(N),N为KEY的数量。
返回值:
- 成功返回1.
- 否则返回0(至少有一个key已经存在)。
DECR 原子减1
DECR key
将 key 中储存的数字值减一。
- 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
- 若值不为数字类型,则返回错误。
- 本操作的值限制在 64 位(bit)有符号数字表示之内。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set age 100
OK
127.0.0.1:6379> decr age
(integer) 99
127.0.0.1:6379> get age
"99"
# key不存在
127.0.0.1:6379> decr name
(integer) -1
# key不为数字
127.0.0.1:6379> set name 'cxian'
OK
127.0.0.1:6379> decr name
(error) ERR value is not an integer or out of range
时间复杂度为O(1)。
返回值:
- 返回执行命令DECR后的值。
- 当值不为数字则报错。
DECRBY 原子减
DECRBY key decrement
将 key 所储存的值减去减量 decrement 。
- 若key不存在,则新给key赋值为0,然后再执行DECRBY操作
- 若key的值不为数字,则返回错误;
- 本操作的值限制在 64 位(bit)有符号数字表示之内。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set age 100
OK
127.0.0.1:6379> DECRBY age 30
(integer) 70
# key不存在
127.0.0.1:6379> DECRBY name 30
(integer) -30
127.0.0.1:6379> set name 'cxian'
OK
# key不为数字
127.0.0.1:6379> DECRBY name 30
(error) ERR value is not an integer or out of range
127.0.0.1:6379>
时间复杂度为O(1)。
返回值:
- 执行命令DECRBY后的值。
- 当值不为数字则报错。
INCR 原子加1
INCR key
将 key 中储存的数字值增一。
- 若key不存在,则新给key赋值为0,然后再执行 INCR 操作
- 若key的值不为数字,则返回错误
- 本操作的值限制在 64 位(bit)有符号数字表示之内。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
# key不存在
127.0.0.1:6379> incr age
(integer) 1
# key存在
127.0.0.1:6379> set age 100
OK
127.0.0.1:6379> incr age
(integer) 101
时间复杂度为O(1)。
返回值:
- 返回INCR命令后key的值。
INCRBY 原子加
INCRBY key increment
所DECR相似,不同在于DECRBY是减,而INCRBY是相加。
GET 取值
GET key
返回 key 所关联的字符串值。
- key 不存在,返回nil
- key 的值不为字符串,返回一个错误(GET只处理字符串)
127.0.0.1:6379> flushdb
OK
# key不存在
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> set age '100'
OK
127.0.0.1:6379> get age
"100"
# key对应的值不为字符串get报错
127.0.0.1:6379> lpush fruits apple banana orange
(integer) 3
127.0.0.1:6379> get fruits
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(1)。
返回值:
- 返回key对应的值。
MGET 批量取值
MGET key [key ...]
依次返回所有(一个或多个)给定 key 的值。
- 当key不存在 或key的值不为字符串,返回nil
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set age 88
OK
127.0.0.1:6379> lpush fruits apple banana orange pear
(integer) 4
# fruits为集合和name不存在,返回nil
127.0.0.1:6379> mget age fruits name
1) "88"
2) (nil)
3) (nil)
时间复杂度O(N),N为key的数量。
返回值:
- 一个包含所有给定 key 的值的列表。
更多命令连接
3.1.1 字符串应用场景
对象缓存
- SET product1: value(json格式数据)
- MSET project:1:name value1 project:1:code value2
分布式锁
- SETNX project:1 value // 获取锁 返回1表示取锁成功,返回0表示取锁失败
// 伪代码,对某个项目id为1001的进行加锁
String key = "project:1001";
try {
// 返回1表示取锁成功
if (0 < SETNX key value) {
// TODO 业务逻辑
}
} finally {
// 执行完业务,删除key释放锁
DEL key;
}
- 为了防止意外终止使finally代码块没有执行,导致死锁,修改如下
// 伪代码,对某个项目id为1001的进行加锁
String key = "project:1001";
try {
// 设置key过期时间为10秒,返回1表示取锁成功
if (0 < (SETNX key value ex 10 nx)) {
// TODO 业务逻辑
}
} finally {
// 执行完业务,删除key释放锁
DEL key;
}
分布式系统全局序序号
- INCRBY projectId 10000:排量生成序列号,根据实际的服务器数量和业务数据量来调整批量生成序列号的数量缓存的机器本地中,来提升性能。(这个只是个简单例子,根据实的业务的复杂性添加相应的逻辑处理)
统计数量
- 统计某广告的pv:INCR advertisement:pv:{广告id}
web集群session共享
- Spring session + redis实现session共享
3.2 Hash常用操作实战
HSET 添加
HSET key field value
将哈希表 key 中的域 field 的值设为 value。
- key不存在,创建新的哈希表并hset操作。
- key存在,覆盖旧值。
127.0.0.1:6379> flushdb
OK
# field不存在,hset成功返回 1
127.0.0.1:6379> hset person name 'cxian'
(integer) 1
127.0.0.1:6379> hset person age '22'
(integer) 1
# field已存在并覆盖值,hset成功返回 0
127.0.0.1:6379> hset person age '25'
(integer) 0
127.0.0.1:6379> set name 100
OK
# 对已存在的key执行hset报错
127.0.0.1:6379> hset name high 1.75
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复试度为O(1)。
返回值:
- 返回1:field不存在并值设置成功。
- 返回0:field已存在并覆盖旧值成功。
- 报错:key不为hash类型。
HSETNX 添加
HSETNX key field value
将哈希表 key 中的域 field 的值设置为 value。
- 若field已存在,该操作无效。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hsetnx person age 10
(integer) 1
# age已存在
127.0.0.1:6379> hsetnx person age 12
(integer) 0
时间复杂度O(1)。
返回值:
- 设置成功返回1.
- field已存在则操作不成功返回0。
HMSET 批量添加
HMSET key field value [field value ...]
同时将多个 field-value (域-值)对设置到哈希表 key 中。
- 此命令会覆盖哈希表中已存在的域。
- 如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hmset person age 12 name cxian
OK
127.0.0.1:6379> hmget person age name
1) "12"
2) "cxian"
时间复杂度O(N),N为field-value的数量。
返回值:
- 执行成功返回OK。
- 当key不是hash表类型时报错。
HGET 获取元素
HGET key field
返回哈希表 key 中给定域 field 的值。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hset person age 88
(integer) 1
127.0.0.1:6379> hget person age
"88"
# key不存在或field不存在
127.0.0.1:6379> hget person1 age
(nil)
127.0.0.1:6379> hget person age1
(nil)
时间复杂度O(1)。
返回给定域的值。
- key不存在或field不存在,返回nil。
HMGET 批量查询
HMGET key field [field ...]
返回哈希表 key 中,一个或多个给定域的值。
- 域不存在于哈希表,那么返回一个 nil 值。
- 若key不存在,列表返回对应field数量的nil值。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hset person age 88
(integer) 1
127.0.0.1:6379> hget person age
"88"
127.0.0.1:6379> hmget person age name address
1) "88"
2) "cxian"
3) (nil)
# key不存在
127.0.0.1:6379> hmget person1 age name
1) (nil)
2) (nil)
时间复杂度O(N),N为field的数量。
返回值:
- 一个包含多个给定域的关联值的表。
- 表值的排列顺序和给定域参数的请求顺序一样。
HGETALL 获取所有
HGETALL key
返回哈希表 key 中,所有的域和值。
- 返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> hset person age 88
(integer) 1
127.0.0.1:6379> hget person age
"88"
127.0.0.1:6379> hset person name cxian
(integer) 1
127.0.0.1:6379> hgetall person
1) "age" # field
2) "88" # value
3) "name"
4) "cxian"
# key不存在
127.0.0.1:6379> hgetall person1
(empty array)
时间复杂度O(N),N为哈希表的大小。
返回值:
- 以列表形式返回哈希表的域和域的值。
- 若key不存在返回空列表。
HINCRBY 增加整数
HINCRBY key field increment
为哈希表 key 中的域 field 的值加上增量 increment。
- 若increment为负数相当于相减。
- 若key或field不存在,创建(默认值为0)并执行hincrby命令。
- 若field对应值不为数字,则报错。
- 本操作的值被限制在 64 位(bit)有符号数字表示之内。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
# key和field不存在
127.0.0.1:6379> hincrby person age 22
(integer) 22
127.0.0.1:6379> hget person age
"22"
# increment为负数
127.0.0.1:6379> hincrby person age -10
(integer) 12
127.0.0.1:6379> hget person age
"12"
127.0.0.1:6379>
127.0.0.1:6379> hset person name cxian
(integer) 1
# field对应值不为数字
127.0.0.1:6379> hincrby person name 12
(error) ERR hash value is not an integer
时间复杂度O(1)。
返回值:
- 返回执行hincrby之后field对应的值。
HINCRBYFLOAT 添加浮点数
HINCRBYFLOAT key field increment
为哈希表 key 中的域 field 加上浮点数增量 increment 。
- 与HINCRBY key field increment相似。
- 不同点是HINCRBYFLOAT的increment必须是双精度浮点数且可以用指数符号形式表示(如2.0e7 、 3e5 、 90e-2等)。
127.0.0.1:6379> hincrbyfloat person age 23.8
"35.8"
127.0.0.1:6379> hincrbyfloat person age -8.9
"26.9"
HLEN 查Field数量
HLEN key
返回哈希表 key 中域的数量。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> hmset person age 23 name cxian
OK
127.0.0.1:6379> hlen person
(integer) 2
时间复杂度O(1)。
返回值:
- 返回哈希表中field的数量。
- key不存在时返回0。
HDEL 删除Field
HDEL key field [field ...]
删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
127.0.0.1:6379> hgetall person
1) "age"
2) "23"
3) "name"
4) "cxian"
127.0.0.1:6379> hdel person age
(integer) 1
# field不存在 或 key不存在
127.0.0.1:6379> hdel person age1
(integer) 0
127.0.0.1:6379> hgetall person
1) "name"
2) "cxian"
时间复杂度O(N),N为field的数量。
返回值:
- 返回被移除的field的数量。
更多命令连接
3.2.1 hash常用应用场景
对象缓存
- HMSET project {projectId}:name value1 {projectId}:code value2
- HMSET project 1001:name value1 1001:code value2
- HMGET project 1001:name 1001:code
比string更好的是hash是一个key
hash有更好的操作
- 获取所有field:hkeys key
- 获取所有field对应的值:hvals key
商城购物车
- 以用户id为key
- 以商品id为field
- 以商品数量为value
操作
- 添加购物车 HSET cart:{userId} {productsId} {数量}
- 数量加1:HINCRBY cart:{userId} {productsId} 1
- 数量减1:HINCRBY cart:{userId} {productsId} -1
- 某商品总数量:HGET cart:{userId} {productsId}
- 商品总数量:HLEN cart:{userId}
- 删除某商品:HDEL cart:{userId} {productsId}
- 获取购物车所有商品:HGETALL cart:{userId}
hash与String相比
- 数据归类整合储存,方便数据管理
- 相比string操作消耗内存与cpu更小
- 相比string储存更节省空间
- key过期设置不能设置在field上
- Redis集群架构下不适合大规模使用(hash分布不均导致某个节点数据量过大问题)
3.3 List常用操作实战
LSET 指定下标添加元素
LSET key index value
将列表 key 下标为 index 的元素的值设置为 value。
- 当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误
- key必须存在
127.0.0.1:6379> flushdb
OK
# key不存在
127.0.0.1:6379> lset mylist 0 apple
(error) ERR no such key
# 初始化key 并插入值
127.0.0.1:6379> lpush mylist app
(integer) 1
127.0.0.1:6379> lindex mylist 0
"app"
# 用lset
127.0.0.1:6379> lset mylist 0 apple
OK
127.0.0.1:6379> lindex mylist 0
"apple"
时间复杂度为O(N)
- 表头和表尾,复杂度为O(1)
- 其它情况为O(N),N为列表的长度
返回值
- 成功返回OK。
- 否则返回错误信息。
LPUSH 将元素插入列表头
LPUSH key value [value ...]
将一个或多个值 value 插入到列表 key 的表头。
- 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头
- 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作
- 当 key 存在但不是列表类型时,返回一个错误
- 允许重复插入
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> lpush mylist apple banana orange pear
(integer) 4
# 重复插入
127.0.0.1:6379> lpush mylist apple banana orange pear
(integer) 8
# 查看列表数据
127.0.0.1:6379> lrange mylist 0 -1
1) "pear"
2) "orange"
3) "banana"
4) "apple"
5) "pear"
6) "orange"
7) "banana"
8) "apple"
时间复杂度为O(1)。
返回值:
- 执行LPUSH后的列表长度。
RPUSH 将元素插入列表尾
RPUSH key value [value ...]
将一个或多个值 value 插入到列表 key 的表尾(最右边)。
- 操作与LPUSH相似,只有一点不同是 RPUSH 是从尾部插入(LPUSH从头插入)。
LPOP 取列表头元素
LPOP key
移除并返回列表 key 的头元素。
- 若列表为空,返回nil
- 若key不存在,返回nil
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> lpush mylist apple banana orange pear
(integer) 4
127.0.0.1:6379> llen mylist
(integer) 4
127.0.0.1:6379> lpop mylist
"pear"
# 头元素已不存在
127.0.0.1:6379> lrange mylist 0 -1
1) "orange"
2) "banana"
3) "apple"
127.0.0.1:6379> lpop mylist
"orange"
127.0.0.1:6379> lpop mylist
"banana"
127.0.0.1:6379> lpop mylist
"apple"
# 列表为空 或 key不存在时
127.0.0.1:6379> lpop mylist
(nil)
127.0.0.1:6379> lpop mylist1
(nil)
时间复杂度为O(1)。
返回值:
- 移除的头元素。
- 若列表为空 或 key不存在时,返回nil。
RPOP 取列表尾元素
RPOP key
操作与LPOP相似
- RPOP是从尾部移除,LPOP是从头部移除
BLPOP 阻塞式取列表头元素
BLPOP key [key ...] timeout
列表的阻塞式(blocking)弹出原语
- timeout单位为秒,若为0 表示无限阻塞
- 它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止
- 当给定多个 key 参数至少有一个不为空列表,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> lpush mylist apple # 初始化列表并添加一个元素
(integer) 1
127.0.0.1:6379> blpop mylist 10
1) "mylist"
2) "apple"
127.0.0.1:6379> blpop mylist 10
(nil)
(10.05s) # 超时秒数,未取出数据退出
127.0.0.1:6379> lpush mylist apple # 添加一个元素
(integer) 1
# 而mylist2不存在 跳过;mylist存在且不为空,紧接着 command 列表的第一个元素被弹
127.0.0.1:6379> blpop mylist2 mylist 10
1) "mylist" # 弹出元素所属的列表
2) "apple" # 弹出元素所属的值
- 所给的key为空 或不存在,命令将阻塞连接
- 直到等到超时退出
- 或直到任何一个key有值为止
- 多客户端执行相同命令时,多个客户端先后放到同一个阻塞队列中,某个key有数据时,先放入阻塞队列的客户端先获取元素
- 在MULTI/EXEC事务的BLPOP中
- 事务行为为了保证事务的原子性,是阻止对key进行push操作的,所以在MULTI/EXEC事务中BLPOP与LPOP一样不会阻塞,对空列表返回nil,对非空列表返回头元素
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> multi # 开启个事务
OK
127.0.0.1:6379(TX)> blpop mylist mylist2 1000 # 对不存在key进行blpop
QUEUED
127.0.0.1:6379(TX)> exec # 提交事务
1) (nil) # 不阻塞立即返回
127.0.0.1:6379> lpush mylist apple # 创建mylist并初始化一个元素
(integer) 1
127.0.0.1:6379> multi # 开启个事务
OK
127.0.0.1:6379(TX)> blpop mylist mylist2 1000 # 对非空列表进行blpop
QUEUED
127.0.0.1:6379(TX)> exec # 提交事务
1) 1) "mylist" # 返回元素所在的列表
2) "apple" # 返回元素
127.0.0.1:6379> multi # 开启个事务
OK
127.0.0.1:6379(TX)> blpop mylist mylist2 1000 # 对空列表进行blpop
QUEUED
127.0.0.1:6379(TX)> exec # 提交事务
1) (nil) # 不阻塞直接返回nil
时间复杂度为o(1)。
返回值:
- 返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
- 如果列表为空,返回一个 nil。
BRPOP 阻塞式取列表尾元素
BRPOP key [key ...] timeout
操作与BLPOP相似
- 不同点:BRPOP是取第一个非空列表的尾部元素;BLPOP是取第一个非空列表的头部元素。
更多命令连接
3.3.1 List常用应用场景举例
栈(Stack)
- LPUSH + LPOP 实现
队列(Queue)
- LPUSH + RPOP 实现
阻塞队列(Block Queue)
-
LPUSH + BRPOP 实现
3.4 SET常用操作实战
SADD 插入集合
SADD key member [member ...]
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
- 假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
- 当 key 不是集合类型时,返回一个错误。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd myset a b c d e f g h i j k l m n # 向key中添加集合元素,key不存在则自动创建空的key集合
(integer) 14
127.0.0.1:6379> set name lisi # 初始化非集合key
OK
127.0.0.1:6379> sadd name zhangsan # 向非集合中执行sadd
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N), N 是被添加的元素的数量。
返回值:
- 被添加到集合中的新元素的数量,不包括被忽略的元素。
- 对非集合执行sadd,报错。
SCARD 取元素数量
SCARD key
返回集合中的元素数量
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> scard myset2 # 不存在key
(integer) 0
127.0.0.1:6379> sadd myset a b c d e f g h i j k l m n
(integer) 14
127.0.0.1:6379> scard myset # 存在集合key
(integer) 14
127.0.0.1:6379> set name lisi # 初始化非集合key
OK
127.0.0.1:6379> scard name # 对非集合key执行scard命令
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(1)。
返回值:
- 不存在key似为空集合,返回0。
- 存在集合key,返回元素个数。
- 对非集合key,报错。
SPOP 随机移除元素
SPOP key
移除并返回集合中的一个随机元素。
- 如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 SRANDMEMBER 命令。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd myset a # 初始化集合
(integer) 1
127.0.0.1:6379> spop myset
"a"
127.0.0.1:6379> spop myset # 集合为空
(nil)
127.0.0.1:6379> spop myset2 # 不存在的key
(nil)
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> spop name # key 不为集合
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(1)。
返回值:
- 被随机移除的元素。
- 当 key 不存在或 key 是空集时,返回 nil。
- 当 key 不为集合,报错。
SREM 移除多个元素
SREM key member [member ...]
移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd myset a b c d e # 初始化集合
(integer) 5
127.0.0.1:6379> srem myset a b c d # 移除 a b c d
(integer) 4
127.0.0.1:6379> srem myset a b c d e
(integer) 1 # 移除 a b c d e,不存在元素忽视了
127.0.0.1:6379> srem myset2 a
(integer) 0 # 移除不存在key似为空集合
127.0.0.1:6379> set name list
OK
127.0.0.1:6379> srem name 1 # key不为集合,报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度为O(N), N 为给定 member 元素的数量。
返回值:
- 不存在key似为空集合,返回0。
- key为集合,返回成功移除的元素的数量(不包括被忽视的元素),不存在的元素直接被忽视。
- key不为集合,报错。
SMEMBERS 取所有成员
SMEMBERS key
返回集合 key 中的所有成员。
- 不存在的 key 被视为空集合。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd s1 a b c d e
(integer) 5
127.0.0.1:6379> smembers s1
1) "d"
2) "b"
3) "a"
4) "c"
5) "e"
127.0.0.1:6379> smembers s2
(empty array)
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> smembers name
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N), N 为集合的基数。
返回值:
- 集合中的所有成员。
- 不存在的key返回空。
- 非集合key,报错。
SRANDMEMBER 取指定数量元素
SRANDMEMBER key [count]
取指定数量count的元素。
- count不指定:默认为1,即随机取一个元素。
- count为正数:count小于集合大小,返回不重复的count个元素的数组;count大于等于集合大小,则返回整个集合的元素。
- count为负数:那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd s1 a b c
(integer) 3
127.0.0.1:6379> srandmember s1
"a"
127.0.0.1:6379> srandmember s1 2
1) "a"
2) "b"
127.0.0.1:6379> srandmember s1 5
1) "b"
2) "a"
3) "c"
127.0.0.1:6379> srandmember s1 -5
1) "a"
2) "c"
3) "a"
4) "c"
5) "c"
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> srandmember lisi
(nil)
时间复杂度:
- 只提供 key 参数时为 O(1) 。
-
如果提供了 count 参数,那么为 O(N) ,N 为返回数组的元素个数。
返回值:
- 只提供 key 参数时,返回一个元素;如果集合为空,返回 nil 。
- 如果提供了 count 参数,那么返回一个数组;如果集合为空,返回空数组。
- 对非集合key执行srandmember返回nil。
SISMEMBER 判断元素是否存在
SISMEMBER key member
判断 member 元素是否集合 key 的成员。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd s1 a b c # 初始化集合
(integer) 3
127.0.0.1:6379> sismember s1 a # 查看是否存在
(integer) 1
127.0.0.1:6379> sismember s1 f
(integer) 0
127.0.0.1:6379> sismember s2 f # 不存在key似为空集合
(integer) 0
127.0.0.1:6379> set name cxian
OK
127.0.0.1:6379> sismember name f # 对非集合key操作,报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(1)。
返回值:
- 存在返回1。
- 不存在返回0。
- 对非集合执行 SISMEMBER 命令,报错。
SUNION 多集合求并集
SUNION key [key ...]
返回一个集合的全部成员,该集合是所有给定集合的并集。
- 不存在的 key 被视为空集。
- 原理:把所有key集合的元素组合在一起并且去重后的元素集合。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd myset a b # 初始化集合
(integer) 2
127.0.0.1:6379> sadd myset2 a b c d # 初始化集合
(integer) 4
127.0.0.1:6379> sunion myset myset2 myset3 # myset3不存在被似为空集合
1) "d"
2) "a"
3) "b"
4) "c"
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> sunion myset name # 有key存在且不为集合,报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N), N 是所有给定集合的成员数量之和。
返回值:
- 并集成员的列表。
- 有key存在且不为集合则报错。
SUNIONSTORE 多集合求并集(存储)
SUNIONSTORE destination key [key ...]
与SUNION操作相似
- 不同点:它将结果保存到 destination 集合,而不是简单地返回结果集。
- 如果 destination 已经存在,则将其覆盖。
- destination 可以是 key 本身。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd s1 a b # 初始化集合
(integer) 2
127.0.0.1:6379> sadd s2 c
(integer) 1
127.0.0.1:6379> sunionstore dest s1 s2 s3 # 取并集
(integer) 3
127.0.0.1:6379> smembers dest # 查看dest信息
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> set name cxian
OK
127.0.0.1:6379> sunionstore dest s1 s2 s3 name # 有非命令key报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N), N 是所有给定集合的成员数量之和。
返回值:
- 结果集中的元素数量。
- 对非集合key执行SUNIONSTORE命令报错。
SINTER 多集合求交集
SINTER key [key ...]
返回所有给定集合的交集。
- 不存在的 key 被视为空集。
- 原理:取都存在于所有key集合中的元素集合。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd s1 a b c d e # 初始化集合
(integer) 5
127.0.0.1:6379> sadd s2 b e f g # 初始化集合
(integer) 4
127.0.0.1:6379> sinter s1 s2 # 取交集
1) "e"
2) "b"
127.0.0.1:6379> sinter s1 s2 s3 # 取交集,有不存在的key似为空集
(empty array)
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> sinter s1 s2 name # 存在不为集合的key报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。
返回值:
- 交集成员的列表(不存在key似为空集合)。
- 存在key不为集合,报错。
SINTERSTORE 多集合求取交集(存储)
SINTERSTORE destination key [key ...]
跟SINTER操作相似。
- 不同点:SINTERSTORE 它将结果保存到 destination 集合中。
- 如果 destination 已经存在,则将其覆盖。
- destination 可以是 key 本身。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd s1 a b d # 初始化集合
(integer) 3
127.0.0.1:6379> sadd s2 d e f # 初始化集合
(integer) 3
127.0.0.1:6379> sinterstore dest s1 s2
(integer) 1
127.0.0.1:6379> smembers dest # 查看集合dest
1) "d"
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> sinterstore dest s1 s2 name # 存在不为集合的key
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。
返回值:
- 结果集中的成员数量。
- 存在key不为集合,报错。
SDIFF 多集合求取差集
SDIFF key [key ...]
取给定集合之间的差集。
- 不存在的key似为空集合
- 原理:以第个key集合为主减去存在于后面所有key集合的并集的元素,剩下的元素集合。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd myset a b c d e # 初始化几个集合key
(integer) 5
127.0.0.1:6379> sadd myset2 d e
(integer) 2
127.0.0.1:6379> sadd myset3 c d
(integer) 2
127.0.0.1:6379> sdiff myset myset2 myset3 # 取三个集合的差集
1) "b"
2) "a"
127.0.0.1:6379> sdiff myset myset2 myset3 myset4 # 取4个集合的差集,其中一个不存在似为空集合
1) "b"
2) "a"
127.0.0.1:6379> set name lisi # 定义一个非集合key
OK
127.0.0.1:6379> sdiff myset myset2 myset3 myset4 name # 有一个key不为集合
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N), N 是所有给定集合的成员数量之和。
返回值:
- 交集成员的列表。
- 若有不存在的key,似为空集合。
- 若有非集合key,报错。
SDIFFSTORE 多集合求取差集(存储)
SDIFFSTORE destination key [key ...]
与SDIFF操作相拟。
- 不同点:SDIFFSTORE 它将结果保存到 destination 集合中。
- 如果 destination 已经存在,则将其覆盖。
- destination 可以是 key 本身。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd s1 'baidu' 'google' 'alibaba' 'banana' # 初始化集合
(integer) 4
127.0.0.1:6379> sadd s2 'apple' 'banana' 'orange' # 初始化集合
(integer) 3
127.0.0.1:6379> sdiffstore dest s1 s2 # 求差集并保存到dest中
(integer) 3
127.0.0.1:6379> smembers dest # 查看dest中元素
1) "baidu"
2) "google"
3) "alibaba"
127.0.0.1:6379> set name cxian
OK
127.0.0.1:6379> sdiffstore dest s1 name # 存在不为集合的key报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N), N 是所有给定集合的成员数量之和。
返回值:
- 结果集中的成员数量。
- 存在key不为集合,报错。
更多命令连接
3.4.1 集合常用应用场景举例
抽奖活动
- 参加抽奖人加入到集合key中。
- 用 SMEMBERS key 可查看所有参加抽奖的人信息。
- 用 SRANDMEMBER 命令随机获取指定数量中奖名单。
- 若每人只能参与一次,用SREM key member [member...] 删除已中奖名单。
CSDN文章点赞收藏(举例假设,不知官方具体实现)
- 点赞:SADD like:{文章id} {用户id}
- 取消点赞:SREM like:{文章id} {用户id}
- 获取点赞用户列表:SMEMBERS like:{文章id}
- 获取点赞数量:SCARD like:{文章id}
CSDN共同关注可能认识人(举例假设,不知官方具体实现)
- 共同关注人求集合交集:SINTER 集合1 [集合2...]。
- 可能认识人:SDIFF 集合2 集合1(集合1为我认识的人集合,集合2为我关注的人关注的人集合)。
简单的搜索等。
3.5 SortedSet常用操作实战
ZADD 加入有序集
ZADD key score member [[score member] [score member] ...]
将一个或多个 member 元素及其 score 值加入到有序集 key 当中。
- 如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。
- score 值可以是整数值或双精度浮点数。
- 如果 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
- 当 key 存在但不是有序集类型时,返回一个错误。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd z1 8 a 1 b 5 c # 对一个不存在的key操作
(integer) 3
127.0.0.1:6379> zadd z1 2 b # 添加已存在的元素
(integer) 0
127.0.0.1:6379> set name cxian
OK
127.0.0.1:6379> zadd name 1 a # 对非有序集key操作,报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂订O(M*log(N)), N 是有序集的基数, M 为成功添加的新成员的数量。
返回值:
- 被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
- 对非有序集key执行zadd命令,报错。
ZCARD 取成员数量
ZCARD key
返回有序集 key 的基数。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd z1 8 a 1 b 5 c
(integer) 3
127.0.0.1:6379> zcard z1 # 对非空有序集执行zcard命令
(integer) 3
127.0.0.1:6379> zcard z2 # 对不存在key执行zcard命令
(integer) 0
127.0.0.1:6379> set name cxian
OK
127.0.0.1:6379> zcard name # 对非有序集执行zcard命令
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(1)。
返回值:
- 当 key 存在且是有序集类型时,返回有序集的基数。
- 当 key 不存在时,返回 0 。
- 当 key 不是有序集时,报错。
ZINCRBY 运算
ZINCRBY key increment member
为有序集 key 的成员 member 的 score 值加上增量 increment 。
- increment 为正值为增加(score 可以是整数值或双精度浮点数)。
- increment 为负值为减(score 可以是整数值或双精度浮点数)。
- key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member 。
- 当 key 不是有序集类型时,返回一个错误。
127.0.0.1:6379[9]> flushdb
OK
127.0.0.1:6379[9]> zadd s1 1000 name
(integer) 1
127.0.0.1:6379[9]> zscore s1 name
"1000"
127.0.0.1:6379[9]> zincrby s1 100 name
"1100"
127.0.0.1:6379> set s3 100
OK
127.0.0.1:6379> zincrby s3 1 name
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度为O(log(N))。
返回值:
- member 成员的新 score 值,以字符串形式表示。
- key不是有序集,报错。
ZRANGE 取区间成员(升序)
ZRANGE key start stop [WITHSCORES]
返回有序集 key 中,指定区间内的成员。
- 其中成员的位置按 score 值递增(从小到大)来排序(递减用 ZREVRANGE 命令)。
- 具有相同 score 值的成员按字典序来排列。
- start和stop:0开始表示第一个成员,1表示第二个成员,以此类推。
- start和stop:-1开始表示最后一个成员,-2表示倒数第二个成员,以此类推。
- start大于stop或者start大于成员数量:返回空列表。
- WITHSCORES选项:将有序集成员及其分值一起返回。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd s1 100 member1
(integer) 1
127.0.0.1:6379> zadd s1 200 member2
(integer) 1
127.0.0.1:6379> zrange s1 0 1 # 显示敬意0到1的成员
1) "member1"
2) "member2"
127.0.0.1:6379> zrange s1 0 5 # stop 下标超出最大下标时的情况
1) "member1"
2) "member2"
127.0.0.1:6379> zrange s1 -1 -1 # 负数情况
1) "member2"
127.0.0.1:6379> zrange s1 2 1 # start 大于 end 情况
(empty array)
127.0.0.1:6379> zrange s1 4 5 # start 大于 成员数量情况
(empty array)
127.0.0.1:6379> zrange s1 0 1 withscores # 添加withscores 选项情况
1) "member1"
2) "100"
3) "member2"
4) "200"
127.0.0.1:6379> set name cxian
OK
127.0.0.1:6379> zrange name 0 1 # 对非有序集合执行zrange命令情况
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
返回值:
- 指定区间内,带有 score 值(可选)的有序集成员的列表。
- 对非有序集合key操作报错。
ZRANGEBYSCORE 按分值排序取成员
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
- 具有相同 score 值的成员按字典序来排列。
- 可选的 LIMIT 参数指定返回结果的数量及区间(就像SQL中的 SELECT LIMIT offset, count ),注意当 offset 很大时,定位 offset 的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N) 时间。
- 可选的 WITHSCORES 参数决定结果集是单单返回有序集的成员,还是将有序集成员及其 score 值一起返回。
- 默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加 ( 符号来使用可选的开区间(小于或大于)。
- min 和 max 可以是 -inf 和 +inf ,这样一来,你就可以在不知道有序集的最低和最高 score 值的情况下,使用 ZRANGEBYSCORE 这类命令。
- min大于max 或 min大于集合成员最大分时,返回空列表。
127.0.0.1:6379[9]> flushdb
OK
127.0.0.1:6379[9]> zadd s1 2500 name1
(integer) 1
127.0.0.1:6379[9]> zadd s1 5000 name2
(integer) 1
127.0.0.1:6379[9]> zadd s1 12000 name3 # 初始化有序集合
(integer) 1
127.0.0.1:6379[9]> zrangebyscore s1 -inf +inf
1) "name1"
2) "name2"
3) "name3"
127.0.0.1:6379[9]> zrangebyscore s1 -inf +inf withscores
1) "name1"
2) "2500"
3) "name2"
4) "5000"
5) "name3"
6) "12000"
127.0.0.1:6379[9]> zrangebyscore s1 -inf 3000 withscores
1) "name1"
2) "2500"
127.0.0.1:6379[9]> zrangebyscore s1 5000 +inf withscores
1) "name2"
2) "5000"
3) "name3"
4) "12000"
127.0.0.1:6379[9]> zrangebyscore s1 8000 +inf withscores
1) "name3"
2) "12000"
127.0.0.1:6379[9]> zrangebyscore s1 8000 +inf
1) "name3"
127.0.0.1:6379[9]> ZRANGEBYSCORE s1 (8000 400000
1) "name3"
时间复杂度O(log(N)+M), N 为有序集的基数, M 为被结果集的基数。
返回值:
- 指定区间内,带有 score 值(可选)的有序集成员的列表。
- key不是有序集,报错。
ZRANK 取成员排名
ZRANK key member。
返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。
- 排名以 0 为底,也就是说, score 值最小的成员排名为 0 。
- 如果想按分值递减排列,用 ZREVRANK 命令。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd s1 5 member1
(integer) 1
127.0.0.1:6379> zadd s1 3 member2
(integer) 1
127.0.0.1:6379> zadd s1 8 member3
(integer) 1
127.0.0.1:6379> zrank s1 member1 # 对有序集执行zrank情况
(integer) 1
127.0.0.1:6379> set s2 cxian
OK
127.0.0.1:6379> zrank s3 member1 # 对不存在key情况
(nil)
127.0.0.1:6379> set s3 beijing # 初始化非有序集合
OK
127.0.0.1:6379> zrank s3 bj # 对非有序集合情况
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(log(N))。
返回值:
- 如果 member 是有序集 key 的成员,返回 member 的排名。
- 如果 member 不是有序集 key 的成员 或 key 不存在,返回 nil 。
- 如果key不是有序集,报错。
ZREM 移除成员
ZREM key member [member ...]
移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。
- 当 key 存在但不是有序集类型时,返回一个错误。
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> zadd s1 5 member1
(integer) 1
127.0.0.1:6379> zadd s1 3 member2
(integer) 1
127.0.0.1:6379> zadd s1 8 member3 # 初始化有序集
(integer) 1
127.0.0.1:6379> zrem s1 member1 member2 # 成员存在情况
(integer) 2
127.0.0.1:6379> zrem s1 member5 # 成员不存在情况
(integer) 0
127.0.0.1:6379> zrem s2 member5 # key不是有序集情况,报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(M*log(N)), N 为有序集的基数, M 为被成功移除的成员的数量。
返回值:
- 被成功移除的成员的数量,不包括被忽略的成员。
- 成员不存在,返回 0。
- key不是有序集,报错。
ZREVRANGE 取区间成员(降序)
ZREVRANGE key start stop [WITHSCORES]
返回有序集 key 中,指定区间内的成员。
- 与ZRNANGE操作相似(详上翻见 ZRNANGE 命令)。
- 不同点:ZREVRANGE 成员的位置按 score 值递减(从大到小)来排列。
127.0.0.1:6379> zadd grade 65 lining
(integer) 1
127.0.0.1:6379> zadd grade 64 verctor
(integer) 1
127.0.0.1:6379> zadd grade 71 unix # 初始化集合
(integer) 1
127.0.0.1:6379> zrange grade 0 -1 withscores # 查看有序集信息
1) "verctor"
2) "64"
3) "lining"
4) "65"
5) "unix"
6) "71"
127.0.0.1:6379> zrevrange grade 0 -1 withscores # 执行zrevrange命令情况
1) "unix"
2) "71"
3) "lining"
4) "65"
5) "verctor"
6) "64"
127.0.0.1:6379> zrevrange name 0 -1 # 非有序集key执行zrevrange命令情况报错
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
返回值:
- 指定区间内,带有 score 值(可选)的有序集成员的列表。
- 对非有序集合key操作报错。
ZREVRANK 取成员提名(降序)
ZREVRANK key member
返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。
- 排名以 0 为底,也就是说, score 值最大的成员排名为 0 。
- 使用 ZRANK 命令可以获得成员按 score 值递增(从小到大)排列的排名
127.0.0.1:6379> zrange grade 0 -1 # 查看集合信息
1) "verctor"
2) "lining"
3) "unix"
127.0.0.1:6379> zrevrank grade lining # 取lining的排名
(integer) 1
127.0.0.1:6379> zrevrank grade baidu # 成员不存在
(nil)
127.0.0.1:6379> get grade1
(nil)
127.0.0.1:6379> zrevrank grade1 baidu # key不存在
(nil)
127.0.0.1:6379> zrevrank name baidu # key存在且不为有序集合
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(log(N))。
返回值:
- 如果 member 是有序集 key 的成员,返回 member 的排名。
- 如果 member 不是有序集 key 的成员 或 key 不存在,返回 nil 。
- key不是有序集,报错。
ZREVRANGEBYSCORE 取分值成员(逆序)
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
返回有序集 key 中, score 值介于 max 和 min 之间(默认包括等于 max 或 min )的所有的成员。有序集成员按 score 值递减(从大到小)的次序排列。
- 与ZRNANGEBYSCORE操作相似(详上翻见 ZRANGEBYSCORE 命令)。
- 不同点:ZREVRANGEBYSCORE 成员的位置按 score 值递减(从大到小)来排列。
127.0.0.1:6379> zrange grade 0 -1 withscores # 查看有序集合信息
1) "verctor"
2) "64"
3) "lining"
4) "65"
5) "unix"
6) "71"
127.0.0.1:6379> zrevrangebyscore grade 90 60 withscores # 执行zrevrangebyscore命令
1) "unix"
2) "71"
3) "lining"
4) "65"
5) "verctor"
6) "64"
时间复杂度O(log(N)+M), N 为有序集的基数, M 为结果集的基数。
返回值:
- 指定区间内,带有 score 值(可选)的有序集成员的列表。
- 对非有序集合key操作报错。
ZSCORE 取成员的分值
ZSCORE key member
返回有序集 key 中,成员 member 的 score 值。
- 如果 member 元素不是有序集 key 的成员,或 key 不存在,返回 nil 。
127.0.0.1:6379> zrange grade 0 -1
1) "verctor"
2) "lining"
3) "unix"
127.0.0.1:6379> zscore grade lining # 取存在成员的情况
"65"
127.0.0.1:6379> zscore grade lining2 # 取不存在成员的情况
(nil)
127.0.0.1:6379> zscore grade2 lining2 # 取不存在key不存在成员的情况
(nil)
127.0.0.1:6379> set grade3 beijing
OK
127.0.0.1:6379> zscore grade3 lining2 # 取存在key不为有序集全情况
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(1)。
返回值:
- member 成员的 score 值,以字符串形式表示。
- 返回nil:key不存在或成员不存在。
- 报错:key存在但不是有序集合。
ZUNIONSTORE 合并多个有序集
语法:ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。
- 默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之和。
- 选项 WEIGHTS:指给定有序集成员指定一个乘法因子,返回时指定的有序集成员的分值均乘以乘法因子。
- 没有指定 WEIGHTS 选项,乘法因子默认设置为 1 。
- 选项 AGGREGATE:两个以上有序集合有相同成员,以SUM|MIN|MAX 来取值,默认为SUM(SUM:分值相加;MIN:取最小的;MAX:取最大的)。
- 不存在的key似为空集合
127.0.0.1:6379> zrange grade 0 -1 withscores # 查看有序集成员信息
1) "verctor"
2) "64"
3) "lining"
4) "65"
5) "unix"
6) "71"
127.0.0.1:6379> zrange grade2 0 -1 withscores # 查看有序集成员信息
1) "ll"
2) "30"
3) "un"
4) "35"
5) "vc"
6) "50"
127.0.0.1:6379> zunionstore dest 2 grade grade2 weights 2 2 # 执行zunionstore
(integer) 6
127.0.0.1:6379> zrange dest 0 -1 withscores # 查看 dest 信息
1) "ll"
2) "60" # 分值已乘以2(原数据是30)
3) "un"
4) "70" # 分值已乘以2(原数据是35)
5) "vc"
6) "100" # 分值已乘以2(原数据是50)
7) "verctor"
8) "128"
9) "lining"
10) "130"
11) "unix"
12) "142"
127.0.0.1:6379> del grade3
(integer) 1
127.0.0.1:6379> zunionstore dest 3 grade grade2 grade3 # 不存在key情况
(integer) 6
127.0.0.1:6379> zadd grade 12 ll # 在grade中添加和grade2相同的成员
(integer) 1
127.0.0.1:6379> zscore dest ll # 查看dest的成员ll的分值
"42"
127.0.0.1:6379> set grade3 beiging
OK
127.0.0.1:6379> zunionstore dest 3 grade grade2 grade3 # key不是有序集合情况
(error) WRONGTYPE Operation against a key holding the wrong kind of value
时间复杂度O(N)+O(M log(M)), N 为给定有序集基数的总和, M 为结果集的基数。
返回值:
- 保存到 destination 的结果集的成员数量。
- key不为有序集,报错。
更多命令连接
3.5.1 SortedSet应用场景举例
统计流量
- 浏览一次加一:ZINCRBY csdn:article:20230921 1 {文章id}
当日浏览量排行前十
-
命令:ZREVRANGE csdn:article:20230921 0 9 WITHSCORES