Redis之基础篇

Redis简介

Redis是一种基于键值对(Key-Value)的NoSQL数据库,它支持string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、HyperLogLog、GEO(地理信息定位)等多种数据结构和算法。因此Redis可以满足多种应用场景。而且因为Redis会将数据存储在内存中,因此它的读写性能非常好,Redis还具有将数据存到快照或者日志上的机制,这便于数据恢复。Redis还提供键过期、发布订阅、事务、流水线、lua脚本等附加功能

Redis特性

  1. 速度快,读写速度据统计可以达到10w/s
  2. 基于键值对的数据结构服务器,支持字符串、哈希、列表、集合等数据结构和算法
  3. 功能丰富,提供键过期、发布订阅、事务、流水线、lua脚本等附加功能
  4. 简单稳定
  5. 支持多种语言的客户端
  6. 提供了RDBAOF两种持久化策略
  7. 支持主从复制
  8. 支持高可用和分布式

Redis的使用场景

  1. 缓存
  2. 排行榜系统
  3. 社交网络点赞、粉丝等功能
  4. 计数器应用如:播放数、浏览数
  5. 消息队列功能

Linux下安装Redis并启动

安装Redis

搭建C语言的编译环境
yum install gcc-c++
gcc --version # 校验是否安装成功
下载Redis

usr文件夹下输入以下命令下载redis

wget https://download.redis.io/releases/redis-6.2.1.tar.gz

解压redis-6.2.1.tar.gz

tar -zxvf redis-6.2.1.tar.gz
编译

进入到redis-6.2.1文件夹中,建入make执行编译,完成后执行make install,自此安装完成。
注意:请预先安装c语言编译环境,否则到此步骤会报错

Redis启动

redis安装完后会产生几个以redis开头的可执行文件,这些Redis Shell可以用来启动、停止Redis。

可执行文件 作用
redis-server 启动Redis
redis-cli Redis客户端
redis-bechmark Redis测试工具
redis-check-aof Redis AOF持久化文件检测和修复工具
redis-check-rdb Redis RDB持久化文件检测和修复工具
前台启动

这种方式会使用Redis默认配置来启动,当退出终端或者按住Ctrl+C就会退出。

redis-server /etc/redis/redis.conf
后台启动

修改redis.conf,找到daemonize,将此参数设置为yes,如下图所示
Redis之基础篇_第1张图片
启动即可

redis-server /etc/redis/redis.conf

Redis关闭服务端

  1. redis-cli shutdown
  2. kill redis进程号

注意最好不要使用kill -9来强制杀死redis服务,这种情况不会做持久化操作,极端情况会造成AOF和复制丢失数据。

Redis的常见操作

查看所有键

该命令会将所有的键输出

127.0.0.1:6379> keys *
(empty array)

添加和删除字符串键值

# 添加字符串
127.0.0.1:6379> set hello zayton
OK
127.0.0.1:6379> set spring boot
OK
127.0.0.1:6379> set java basic
OK

# 查看所有键
127.0.0.1:6379> keys *
1) "java"
2) "spring"
3) "hello"

# 删除字符串
127.0.0.1:6379> del hello
(integer) 1

# 再次查看所有键
127.0.0.1:6379> keys *
1) "java"
2) "spring"
#插入一个列表类型的键值对
127.0.0.1:6379> rpush mylist a b c d e
(integer) 5

检查key是否存在

# exists key
127.0.0.1:6379> exists java
(integer) 1

该命令如果键存在则返回1,不存在则返回0

设置键过期

Redis支持键过期时间,当超过过期时间后,会自动删除键,下面我们给键设置10秒过期,然后用ttl命令观察剩余过期时间。

127.0.0.1:6379> set hello zayton
OK
127.0.0.1:6379> expire hello 10
(integer) 1
127.0.0.1:6379> ttl hello
(integer) 8
127.0.0.1:6379> ttl hello
(integer) 6
127.0.0.1:6379> ttl hello
(integer) 4
127.0.0.1:6379> ttl hello
(integer) 4
127.0.0.1:6379> ttl hello
(integer) 1
127.0.0.1:6379> ttl hello
(integer) -2
127.0.0.1:6379>

ttl命令会返回三种返回值:

  1. 大于0表示剩余过期时间
  2. -1表示没设置过期时间
  3. -2表示键不存在

查看键的数据结构

127.0.0.1:6379> type java
string
127.0.0.1:6379> type mylist
list

字符串类型常见命令

设置值

set key value [ex seconds]  [px milliseconds] [nx|xx]

示例,设置一个key为hello,value为world的字符串

127.0.0.1:6379> set hello world
OK
  • ex seconds:为键设置秒级过期时间
  • px milliseconds:为键设置毫秒级过期时间
  • nx:若键不存在才能设置成功
  • xx:若键存在才能设置成功

setnx、setex

setnx的作用和set的nx选项一样,都是键不存在才能设置成功。因为redis单线程命令处理机制,如果有多个客户端同时执行setnx key value,则只会有一个成功,因此setnx常用于分布式锁,是一种乐观锁。上述设置了key为hello的键值对,下面我们用setnx命令再次设置,会发现值没有变化。

127.0.0.1:6379> setnx hello world2
(integer) 0
127.0.0.1:6379> get hello
"world"

setex相当于set指令的ex选项

# 设置一个10s过期的键值对
127.0.0.1:6379> SETEX zayton 10 squid
OK
127.0.0.1:6379> get zayton
"squid"
127.0.0.1:6379> get zayton
"squid"
# 10s后查询
127.0.0.1:6379> get zayton
(nil)

获取值

get key

批量设置值、获取值

mset key value [key value ...]
gset key [key ...]

示例

127.0.0.1:6379> mset a 1 b 2 c 3
OK
127.0.0.1:6379> mget a b c
1) "1"
2) "2"
3) "3"

注意:如果需要从redis中获取大量key值,建议使用mget
执行n次get命令请求模型如下图所示

# 耗时
n次get时间 = n次网络时间 + n次命令时间

Redis之基础篇_第2张图片
而执行一次mget命令请求模型如下图所示

#耗时
n次get时间 = 1次网络时间 + n次命令时间

Redis之基础篇_第3张图片
从耗时我们可以看出,一次mget请求只需要消耗一次网络时间,而n次get请求需要消耗n次网络时间,故而使用mget有助于提高业务处理效率。

计数

incr key命令用于对值进行自增操作,若值存在且为整数,则自增;若值不存在,则创建并设置初始值为1;若值存在且非整数,则返回错误。并且因为redis是单线程架构,无需考虑使用CAS机制来保证线程安全,而是在服务端中都按顺序自增,所以性能比较好。

127.0.0.1:6379> incr num
(integer) 1
127.0.0.1:6379> set zayton squid
OK
127.0.0.1:6379> incr zayton
(error) ERR value is not an integer or out of range
127.0.0.1:6379> incr num
(integer) 2

除了incr key命令,redis还提供了decr key(自减)incrby key (自增指定数字)
decrby key(自减指定数字)incrbyfloat key(自增浮点数)

127.0.0.1:6379> decr num
(integer) 1
127.0.0.1:6379> incrby num 10
(integer) 11
127.0.0.1:6379> decrby num 5
(integer) 6
127.0.0.1:6379> incrbyfloat floatNum 2.2
"2.2"

字符串类型典型使用场景

缓存功能

如下所示,可将常用的数据库数据存到redis中提高访问数据,建议使用的key为表名:对象名:id,例如userInfo:user:1
Redis之基础篇_第4张图片
用于获取用户的基础信息示例

public UserInfo getUserInfo(long id){
	userRedisKey = "user:info:" + id;
	// 从Redis获取值
	value = redis.get(userRedisKey);
	if (value != null) {
	// 将值进行反序列化为UserInfo并返回结果
	userInfo = deserialize(value);
	return userInfo;
}

计数

可以用作视频播放量计数,如下代码示例

public long incrVideoCounter(long id) {
	key = "video:playCount:" + id;
	return redis.incr(key);
}

共享Session

为了保证用户信息在集群场景下能够共用一个session,可以在另起一台服务器搭建redis用来保存用户信息,避免用户因为负载均衡在各个服务器之间每次都要重新登陆。
Redis之基础篇_第5张图片

限速

在日常中会发现很多验证码登录限制每分钟获取验证码的频率,这是出于安全考虑设计的,那么可以用redis实现该功能。

phoneNum = "138xxxxxxxx";
key = "shortMsg:limit:" + phoneNum;
// SET key value EX 60 NX
isExists = redis.set(key,1,"EX 60","NX");
if(isExists != null || redis.incr(key) <=5){
// 通过
}else{
// 限速
}

哈希类型常见命令

哈希类型指存储键值对的数据结构,也叫做字典、关联数组;例如value={{field1,value1},…{filedN,valueN}}。

Redis之基础篇_第6张图片

设置值和获取值

# 设置值
hset key field value
# 获取值
hget key field 

示例

127.0.0.1:6379> hset user:1 name squid
(integer) 1
127.0.0.1:6379> hget user:1 name
"squid"

删除field

HDEL key field

示例

127.0.0.1:6379> hdel user:1 name
(integer) 1

hdel可以删除一个或多个field,返回结果为成功删除filed的个数

计算哈希类型的field的个数

hlen key

示例

127.0.0.1:6379> hlen user:1
(integer) 1

批量设置值、获取值

hmset key field value [field value ...]
hmget key field [field ...]

示例

127.0.0.1:6379> hmset user:1 name zayton age 18 sex male
OK
127.0.0.1:6379> hmget user:1 name age sex
1) "zayton"
2) "18"
3) "male"

判断field是否存在

hexists key field

示例

127.0.0.1:6379> hexists user:1 name
(integer) 1

获取所有field、所有value、所有field-value

# 获取所有field
hkeys key
# 获取所有value
hvals key
# 获取所有field-value
hgetall key

示例

127.0.0.1:6379> hkeys user:1
1) "name"
2) "age"
3) "sex"
127.0.0.1:6379> hvals user:1
1) "zayton"
2) "18"
3) "male"
127.0.0.1:6379> hgetall user:1
1) "name"
2) "zayton"
3) "age"
4) "18"
5) "sex"
6) "male"

建议:若开发过程中果一定要获取全部field-value,可以使用hscan命令,而非hgetall,避免造成redis拥堵。

自增filed

hincrby key field
hincrbyfloat key field

示例

127.0.0.1:6379> hincrby hash num 1
(integer) 1
127.0.0.1:6379> hincrbyfloat hash money 1.5
"1.5"

计算field的长度

hstrlen key field

示例

# 获取user:1 的name的长度
127.0.0.1:6379> HSTRLEN user:1 name
(integer) 6
127.0.0.1:6379>

哈希类型命令的时间复杂度

命令 时间复杂度
hset key field value O(1)
hget key field O(1)
hdel key field [field …] O(k),k是field个数
hlen key O(1)
hgetall key O(n),n是field总数
hmget field [field …] O(k),k是field个数
hmset field value [field value …] O(k),k是field个数
hexists key field O(1)
hkeys key O(n),n是field总数
hvals key O(n),n是field总数
hsetnx key field value O(1)
hincrby key field increment O(1)
hincrbyfloat key field increment O(1)
hstrlen key field O(1)

哈希类型典型使用场景

在日常开发中,如果我们要缓存某行用户信息,那么使用哈希类型存储非常合适不过了。
Redis之基础篇_第7张图片
使用哈希类型缓存信息主要有以下原因

  • 相较于字符串(占用过多的键,内存占用量较大),哈希内聚更好更易于维护大量的用户信息。
  • 如果使用序列化字符串存储,序列化和反序列化有一定的开销,同时每次更新属性都需要把全部数据取出进行反序列化,更新后再序列化到Redis中。
  • 操作简单,修改用户字段更加方便,使用合理可以减少内存空间的使用。
    Redis之基础篇_第8张图片

但是需要注意的是哈希存储相对二维表更加稀疏,如上图,二维表中null的数据,在哈希表中key是完全不存在的,用户使用时需要考虑到这一点。

列表类型常见命令

列表的概念与Java中的List差不多,都是线性结构,可以用来存储多个有序的字符串,允许重复元素,它可以充当队列和栈。

添加操作

从右边插入元素

rpush key value [value ...]

示例

# 右边一次插入 a b c d e f
127.0.0.1:6379> rpush list a b c d e f
(integer) 6
# lrange key start stop命令可以从左到右获取指定范围内的列表元素
127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"

从左边插入元素

lpush key value [value ...]

示例

127.0.0.1:6379> lpush leftList e f g
(integer) 3
127.0.0.1:6379> lrange leftList 0 -1
1) "g"
2) "f"
3) "e"

向某个元素前或者后插入元素

linsert key before|after pivot value

示例:向列表list中的a元素后插入元素s

127.0.0.1:6379> linsert list after a s
(integer) 7
127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "s"
3) "b"
4) "c"
5) "d"
6) "e"
7) "f"

查找操作

获取指定范围内的元素列表

lrange key start end

示例

# 查询列表list 下标0-2的元素
127.0.0.1:6379> lrange list 0 2
1) "a"
2) "s"
3) "b"
# 查询列表list所有元素
127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "s"
3) "b"
4) "c"
5) "d"
6) "e"
7) "f"
# 查询不存在的列表list2的元素
127.0.0.1:6379> lrange list2 0 1
(empty array)

获取列表指定索引下标的元素

lindex key index

示例

127.0.0.1:6379> lindex list 3
"c"

获取列表长度

llen key

示例

127.0.0.1:6379> llen list
(integer) 7

删除操作

从列表左侧弹出元素

lpop key

示例

127.0.0.1:6379> lpop list
"a"
127.0.0.1:6379> lrange list 0 -1
1) "s"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"

从列表右侧弹出

rpop key

示例

127.0.0.1:6379> rpop list
"f"
127.0.0.1:6379> lrange list 0 -1
1) "s"
2) "b"
3) "c"
4) "d"
5) "e"

删除指定元素

lrem key count value

分为以下三种情况:

  • count>0,从左到右,删除最多count个元素。
  • count<0,从右到左,删除最多count绝对值个元素
  • count=0,删除所有。
    示例
127.0.0.1:6379> lrange list 0 -1
1) "s"
2) "b"
3) "c"
4) "d"
5) "e"
127.0.0.1:6379> lrem list 1 s
(integer) 1
127.0.0.1:6379> lrem list -1 e
(integer) 1
127.0.0.1:6379> lrem list 0 d
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "b"
2) "c"

按照索引范围修剪列表

ltrim key start end

示例:保留列表list第2个到第5个元素

127.0.0.1:6379> lpush list a a b d
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "b"
3) "a"
4) "a"
5) "b"
6) "c"
127.0.0.1:6379> ltrim list 1 4
OK
127.0.0.1:6379> lrange list 0 -1
1) "b"
2) "a"
3) "a"
4) "b"

修改操作

修改指定索引下标的元素

lset key index newValue

示例:在列表list下标为4的位置插入元素‘zayton’

127.0.0.1:6379> lset list 3 zayton
OK
127.0.0.1:6379> lrange list 0 -1
1) "b"
2) "a"
3) "a"
4) "zayton"

阻塞操作

blpop key [key ...] timeout
brpop key [key ...] timeout

blpop示例,若列表为空,当timeout大于0时,时间耗尽后返回nil;当tinmeout等于0时,一直阻塞等待,直到列表有数据。若列表不为空,当timeout大于0时,时间耗尽后返回数据;当timeout等于0时,立即返回数据。

127.0.0.1:6379> brpop blist 3
(nil)
(3.02s)
127.0.0.1:6379> bprop list 0
# 此时通过另一个客户端push元素zayton,该阻塞会弹出元素zayton
127.0.0.1:6379> brpop blist 0
1) "blist"
2) "zayton"
(61.12s)

列表命令时间复杂度

命令 时间复杂度
rpush key value [value…] O(k),k是field个数
lpush key value [value …] O(k),k是field个数
linsert key beforelafter pivot value O(n),n是pivot 距离列表头或尾的距离
lrange key start end o(s+n),s是start偏移量,n是start到end的范围
lindex key index O(n),n是索引的偏移量
llen key O(1)
lpop key O(1)
rpop key O(1)
lrem count value O(n),n是field总数
ltrim key start end O(n),n是要裁剪的元素总数
lset key index value O(n),n是索引的偏移量
blpop brpop O(1)

列表类型典型使用场景

Redis的lpush+brpop命令组合即可实现阻塞队列,如下图,每个消费者只需要关注自己需要的文章列表即可,生产者只需不断使用;push添加文章即可。
Redis之基础篇_第9张图片
关于列表更多的使用口诀如下:

  • lpush+lpop=Stack(栈)
  • lpush+rpop=Queue(队列)
  • lpsh+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息队列)

集合类型常见命令

集合类型可以保存多个字符串元素,但它的元素是无序的且不能重复,一个集合最多可以存储2^32-1个元素。接下来我们来说说它常见的命令:

添加操作

sadd key element [element ...]

示例,可以看到第二次添加的元素并未成功

127.0.0.1:6379> sadd set a b c
(integer) 3
127.0.0.1:6379> sadd set a b
(integer) 0

删除操作

srem key element [element ...]

示例

127.0.0.1:6379> srem set a b
(integer) 2
127.0.0.1:6379> srem set zayton
(integer) 0

计算元素个数

scard的时间复杂度为O(1),它不会遍历集合所有元素,而是通过Redis内部的变量得来的。

scard key

示例

127.0.0.1:6379> scard set
(integer) 1

判断元素是否在集合中

sismember key element

示例

# 不存在则返回0
127.0.0.1:6379> sismember set a
(integer) 0
# 存在则返回1
127.0.0.1:6379> sismember set c
(integer) 1

随机从集合返回指定个数元素

srandmember key [count]

示例

127.0.0.1:6379> sadd set a b d e
(integer) 4
127.0.0.1:6379> srandmember set 3
1) "e"
2) "a"
3) "b"
# count不填默认为1
127.0.0.1:6379> srandmember set
"a"

从集合随机弹出元素

srandmember相似,只不过spop 会将元素从集合中删除

spop key

示例

127.0.0.1:6379> spop set
"c"
127.0.0.1:6379> smembers set
1) "e"
2) "a"
3) "d"
4) "b"
# Redis从3.2版本开始,spop也支持[count]参数
127.0.0.1:6379> spop set 2
1) "e"
2) "d"
127.0.0.1:6379> smembers set
1) "a"
2) "b"

获取所有元素

smembers key

示例

127.0.0.1:6379> smembers set
1) "a"
2) "b"

求多个集合的交集

sinter key [key ...]

示例

127.0.0.1:6379> sadd set1 a b c d
(integer) 4
127.0.0.1:6379> sadd set2 a b e f
(integer) 4
127.0.0.1:6379> sinter set1 set2
1) "b"
2) "a"

求多个集合的并集

sunion key [key ...]

示例

127.0.0.1:6379> sunion set1 set2
1) "e"
2) "f"
3) "a"
4) "d"
5) "c"
6) "b"

求多个集合的差集

这个差集指的是首个集合中有的而其他集合中没有的元素。

sdiff key [key ...]

示例

127.0.0.1:6379> sdiff set1 set2
1) "d"
2) "c"

将交集、并集、差集的结果保存

sinterstore destination key [key ...]
sunionstore destination key [key ...]
sdiffstore destination key [key ...]

示例

127.0.0.1:6379> sinterstore set3 set1 set2
(integer) 2
127.0.0.1:6379> smembers set3
1) "a"
2) "b"
127.0.0.1:6379> sunionstore set4 set1 set2
(integer) 6
127.0.0.1:6379> smembers set4
1) "e"
2) "f"
3) "a"
4) "d"
5) "c"
6) "b"
127.0.0.1:6379> sdiffstore set5 set1 set2
(integer) 2
127.0.0.1:6379> smembers set5
1) "d"
2) "c"

集合类型命令的时间复杂度

命令 时间复杂度
zadd key score member [score member …] O(k×1og(n)),h是添加成员的个数,"是当前有序集合成员个数
zcard key O(1)
scard key O(1)
sismember key element O(1)
srandmember key [count] O(count)
spop key O(1)
smembers key O(n) ,n是元素总数
sinter key [key …]或者 sinterstore O(m*k),k是多个集合中元素最少的个数,m是键个数
sunion key [key …]或者 sunionstore O(k),k是多个集合元素个数和
sdiff key [key …]或者 sdiffstore O(k),k是多个集合元素个数和

集合类型典型使用场景

  • sadd=Tagging(标签,例如体育网站对各类体育类型的标签)
  • spop/srandmember=Random item(生成随机数,比如抽奖)
  • sadd+sinter=Social Graph(社交需求)

有序集合类型常见命令

与集合差不多,相比集合多了score属性,使得集合有序,且它保留了集合的不可重复元素,但score是可重复的。
Redis之基础篇_第10张图片

添加操作

zadd key score member [score member ...]

示例

127.0.0.1:6379> zadd user:ranking 1 zayton 2 jack 3 james
(integer) 3

redis3.2添加了四个选项:

  1. nx:member必须不存在,才可以设置成功,用于添加。
  2. xx:member必须存在,才可以设置成功,用于更新。
  3. ch:返回此次操作后,有序集合元素和分数发生变化的个数
  4. incr:对score做增加,相当于后面介绍的zincrby。
    相比于集合多了排序字段,但是添加元素也由O(1)变为O(log(n))。

计算指定key的有序集合的大小

zcard key

示例

127.0.0.1:6379> zcard user:ranking
(integer) 3

计算某个成员的分数

zscore key member

示例

127.0.0.1:6379> zscore user:ranking zayton
"1"
# 如果成员不存在则返回nil
127.0.0.1:6379> zscore user:ranking squid
(nil)

计算成员的排名

# 升序排名
zrank key member
# 降序排名
zrevrank key member

示例

127.0.0.1:6379> zrank user:ranking zayton
(integer) 0
127.0.0.1:6379> zrevrank user:ranking zayton
(integer) 2

删除成员

zrem key member [member ...]

示例

127.0.0.1:6379> zrem user:ranking zayton
(integer) 1

增加成员的分数

zincrby key increment member

示例

127.0.0.1:6379> zincrby user:ranking 20 jack
"22"
127.0.0.1:6379> zincrby user:ranking 4 jack
"26"

获取指定排名范围内的成员以及score

zrange key start end [withscores]
zrevrange key start end [withscores]

示例

127.0.0.1:6379> zrange user:ranking 0 -1 withscores
1) "james"
2) "3"
3) "jack"
4) "26"

返回指定分数范围的成员

zrangebyscore表示升序,zrevrangebyscore表示降序,min和max还支持开区间(小括号)和闭区间(中括号),-inf和+inf分别代表无限小和无限大

zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores] [limit offset count]

示例

127.0.0.1:6379> zrangebyscore user:ranking 0 50 withscores
1) "james"
2) "3"
3) "jack"
4) "26"
# 获取20到无限大的成员
127.0.0.1:6379> zrangebyscore user:ranking (20 +inf withscores
1) "jack"
2) "26"

返回指定分数范围成员个数

zcount key min max

示例

127.0.0.1:6379> zcount user:ranking 10 30
(integer) 1

删除指定排名内的升序元素

zremrangebyrank key start end

示例

127.0.0.1:6379> zadd user:ranking 40 zayton
(integer) 1
127.0.0.1:6379> zrange user:ranking 0 -1
1) "james"
2) "jack"
3) "zayton"
127.0.0.1:6379> zremrangebyrank user:ranking 0 2
(integer) 3

删除指定分数范围的成员

zremrangebyscore key min max

示例

127.0.0.1:6379> zadd user:ranking 10 zayton 24 jack 26 james 35 squid
(integer) 4
127.0.0.1:6379> zremrangebyscore user:ranking 0 25
(integer) 2

求多个集合的交集

zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]

这个命令参数较多,下面分别进行说明:

  • destination:交集计算结果保存到这个键。
  • numkeys:需要做交集计算键的个数。
  • key[key…]:需要做交集计算的键。
  • weights weight[weight…]:每个键的权重,在做交集计算时,每个键中的每个member会将自己分数乘以这个权重,每个键的权重默认是1。
  • aggregate sum|min|max:计算成员交集后,分值可以按照sum(和)、min(最小值)、max(最大值)做汇总,默认值是sum。
    示例
127.0.0.1:6379> zinterstore zset3 2 zset1 zset2
(integer) 2
127.0.0.1:6379> zrange zset3 0 -1 withscores
1) "jack"
2) "73"
3) "squid"
4) "135"
# zset2的权重变为0.5,并且取两个集合中最大值
127.0.0.1:6379> zinterstore zset3 2 zset1 zset2  weights 1 0.5 aggregate max
(integer) 2
127.0.0.1:6379> zrange zset3 0 -1 withscores
1) "jack"
2) "24.5"
3) "squid"
4) "50"

求多个集合的并集

zunionstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]

示例

127.0.0.1:6379> zunionstore zset4 2 zset1 zset2
(integer) 7
127.0.0.1:6379> zrange zset4 0 -1 withscores
 1) "zayton"
 2) "10"
 3) "tom"
 4) "19"
 5) "james"
 6) "26"
 7) "jack"
 8) "73"
 9) "jerry"
10) "77"
11) "mike"
12) "101"
13) "squid"
14) "135"

有序集合命令的时间复杂度

命令 时间复杂度
zadd key score member [score member …] O(k*log(n)),是添加成员的个数,n是当前有序集合成员个数
zcard key O(1)
zscore key member O(1)
zrank key member
zrevrank key member
O(log(n)),n 是当前有序集合成员个数
zrem key member [member …] O(k*log(n)),是删除成员的个数,n是当前有序集合成员个数
zincrby key increment member O(log(n)),n 是当前有序集合成员个数
zrange key start end [withscores]
zrevrange key start end [withscores]
O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数
zrangebyscore key max min [withscores]
zrevrangebyscore key max min [withscores]
O(log(n)+k),k是要获取的成员个数,n是当前有序集合成员个数
zcount O(log(n)),n 是当前有序集合成员个数
zremrengebyrank key start end O(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数
zremrangebyscore key min max O(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数
zinterstore destination numkeys key [key …] O(nk+O(mlog(m)),n是成员数最小的有序集合成员个数,k是有序集合的个数,m 是结果集中成员个数
zunionstore destination numkeys key [key …] O(nk+O(mlog(m)),n是成员数最小的有序集合成员个数,k是有序集合的个数,m 是结果集中成员个数

有序集合典型使用场景

可用于点赞、播放量排行榜等。
例如点赞功能:

# 张三获得10个点赞数
127.0.0.1:6379> zadd user:ranking:20230901 10 zhangsan
(integer) 1
# 小三获得3个点赞数
127.0.0.1:6379> zadd user:ranking:20230901 3 xiaosan
(integer) 1
# 老三获得6个点赞数
127.0.0.1:6379> zadd user:ranking:20230901 6 laosan
(integer) 1
# 张三点赞数+1
127.0.0.1:6379> zincrby user:ranking:20230901 1 zhangsan
"11"
# 查看点赞数前三
127.0.0.1:6379> zrevrange user:ranking:20230901 0 2
1) "zhangsan"
2) "laosan"
3) "xiaosan"
# 张三被取消一个点赞
127.0.0.1:6379> zincrby user:ranking:20230901 -1 zhangsan
"10"
127.0.0.1:6379> zrevrange user:ranking:20230901 0 2
1) "zhangsan"
2) "laosan"
3) "xiaosan"
# 小三是作弊的,被删掉
127.0.0.1:6379> zrem user:ranking:20230901 xiaosan
(integer) 1
127.0.0.1:6379> zrevrange user:ranking:20230901 0 2
1) "zhangsan"
2) "laosan"

参考

https://book.douban.com/subject/26971561/

你可能感兴趣的:(redis,redis,数据库,缓存)