服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Redis - Redis核心数据结构实战与高性能解析

Redis核心数据结构实战与高性能解析

2023-10-16 16:18小贤java Redis

本文将详细的为大家介绍Redis核心数据结构实战与高性能解析,有需要的朋友可以参考下

一、安装Redis

在MAC环境。

简单的Docker安装Redis见:安装Redis

二、Redis线程与高性能

2.1 Redis是单线程么?

Redis是单线程主要体现在Redis的网络IO和键值对的读写是由一个线程来完成的。但实际Redis并不是单线程,如持久化、数据过期删除和数据同步等是由其它线程来完成的,即Redis是有多个线程的。

2.2 Redis读写是单线程为何这么快?

  1. 数据存储在内在中,所有运算都在内行中完成
  2. 单线程也避免了多线程切换造成的资源损耗(注:因为是单线程,生产环境对Redis的操作是有严格要求的)

2.3 Redis如何处理并发操作命令?

Redis的IO多路复用:redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到 文件事件分派器,事件分派器将事件分发给事件处理器。如下图所示:

Redis核心数据结构实战与高性能解析

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的配置项信息。

三、核心数据结构实战

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 的值的列表。
更多命令连接

Redis 字符串操作实战(全)_小贤java的博客-CSDN博客SET存入字符串键值,对如果 key 已经持有其他值, set 就覆写旧值,无视类型。对于某个原本带有生存时间(TTL)的键来说, 当 set 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。时间复杂度为O(1)。SET 成功时才返回OK。SETNX key value(set if not exists的简写):将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。时间复杂度为O(1)。成功返回OK,否则返回nil。

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的数量。
更多命令连接

Redis 哈希表操作实战(全)_小贤java的博客-CSDN博客HMSET key field value [field value ...]:同时将多个 field-value (域-值)对设置到哈希表 key 中。HDEL key field [field ...]:删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。HMGET key field [field ...]:返回哈希表 key 中,一个或多个给定域的值。HGET key field:返回哈希表 key 中给定域 field 的值。HKEYS key:返回哈希表 key 中的所有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有值为止

Redis核心数据结构实战与高性能解析

  • 多客户端执行相同命令时,多个客户端先后放到同一个阻塞队列中,某个key有数据时,先放入阻塞队列的客户端先获取元素

Redis核心数据结构实战与高性能解析

  • 在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是取第一个非空列表的头部元素。
更多命令连接

Redis 列表操作实战(全)_小贤java的博客-CSDN博客LTRIM key start stop:只保留指定区间 [start, stop] 内的元素,不在指定区间之内的元素都将被删除。LRANGE key start stop:返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。LPUSHX key value:将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。LSET key index value:将列表 key 下标为 index 的元素的值设置为 value。

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不为集合,报错。
更多命令连接

Redis 集合操作实战(全)_小贤java的博客-CSDN博客SREM key member [member ...]:移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。SUNION key [key ...]:返回一个集合的全部成员,该集合是所有给定集合的并集。时间复杂度O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。时间复杂度O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。时间复杂度O(N), N 是所有给定集合的成员数量之和。

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不为有序集,报错。
更多命令连接

Redis 有序集合操作实战(全)_小贤java的博客-CSDN博客有序集成员按 score 值递减(从大到小)的次序排列。时间复杂度O(N*K)+O(M*log(M)), N 为给定 key 中基数最小的有序集, K 为给定有序集的数量, M 为结果集的基数。时间复杂度O(log(N)+M), N 为有序集的基数, M 为值在 min 和 max 之间的元素的数量。时间复杂度O(N)+O(M log(M)), N 为给定有序集基数的总和, M 为结果集的基数。时间复杂度O(M*log(N)), N 为有序集的基数, M 为被成功移除的成员的数量。

3.5.1 SortedSet应用场景举例

统计流量

  • 浏览一次加一:ZINCRBY  csdn:article:20230921  1  {文章id}

当日浏览量排行前十

  • 命令:ZREVRANGE  csdn:article:20230921  0  9  WITHSCORES

3.6 key常用操作实战

详见:Redis key操作实战(全)_小贤java的博客-CSDN博客DEL key [key ...]:删除给定的一个或多个key。EXPIRE key seconds:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。RESTORE key ttl serialized-value:反序列化给定的序列化值,并将它和给定的 key 关联。TTL key:以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)PERSIST key:将这个 key 从(带生存时间 key )的过期时间删除。

到此这篇关于Redis核心数据结构实战与高性能解析的文章就介绍到这了,更多相关内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文地址:https://blog.csdn.net/imwucx/article/details/132900387

延伸 · 阅读

精彩推荐
  • Redis关于redis的延迟双删策略总结

    关于redis的延迟双删策略总结

    这篇文章主要介绍了关于redis的延迟双删策略总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    Hellboy_M12252022-08-26
  • RedisRedis中的BigKey问题排查与解决思路详解

    Redis中的BigKey问题排查与解决思路详解

    Redis是一款性能强劲的内存数据库,但是在使用过程中,我们可能会遇到Big Key问题,这个问题就是Redis中某个key的value过大,所以Big Key问题本质是Big Value问...

    Booksea8612023-04-03
  • RedisRedis分布式锁的实现方式

    Redis分布式锁的实现方式

    本文主要介绍了Redis分布式锁的实现方式,分布式锁是 满足分布式系统或集群模式下多进程可见并且互斥的锁。感兴趣的同学可以参考阅读...

    哪 吒8462023-04-04
  • RedisRedis热点之底层实现篇

    Redis热点之底层实现篇

    Redis提供了Java、C/C++、C#、 PHP 、JavaScript、 Perl 、Object-C、Python、Ruby、Erlang、Golang等多种主流语言的客户端,因此无论使用者是什么语言栈总会找到属于自己...

    今日头条2142020-05-27
  • RedisRedis教程(十四):内存优化介绍

    Redis教程(十四):内存优化介绍

    这篇文章主要介绍了Redis教程(十四):内存优化介绍,本文讲解了特殊编码、BIT和Byte级别的操作、尽可能使用Hash等内容,需要的朋友可以参考下 ...

    Redis教程网5242019-10-24
  • Redis使用注解实现Redis缓存功能

    使用注解实现Redis缓存功能

    这篇文章主要为大家详细介绍了使用注解实现Redis缓存功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    远走与梦游9422022-07-28
  • Redis关于Redis未授权访问漏洞利用的介绍与修复建议

    关于Redis未授权访问漏洞利用的介绍与修复建议

    Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,下面这篇文章主要给大家介绍了...

    burlin5102019-11-06
  • Redisredis 解决库存并发问题实现数量控制

    redis 解决库存并发问题实现数量控制

    本文主要介绍了redis 解决库存并发问题实现数量控制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们...

    笨笨韩10302022-10-14