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-cliRedis客户端
redis-bechmarkRedis测试工具
redis-check-aofRedis AOF持久化文件检测和修复工具
redis-check-rdbRedis RDB持久化文件检测和修复工具
前台启动

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

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

修改redis.conf,找到daemonize,将此参数设置为yes,如下图所示
在这里插入图片描述
启动即可

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次命令时间

在这里插入图片描述
而执行一次mget命令请求模型如下图所示

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

在这里插入图片描述
从耗时我们可以看出,一次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
在这里插入图片描述
用于获取用户的基础信息示例

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实现该功能。

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}}。

在这里插入图片描述

设置值和获取值

# 设置值
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 valueO(1)
hget key fieldO(1)
hdel key field [field …]O(k),k是field个数
hlen keyO(1)
hgetall keyO(n),n是field总数
hmget field [field …]O(k),k是field个数
hmset field value [field value …]O(k),k是field个数
hexists key fieldO(1)
hkeys keyO(n),n是field总数
hvals keyO(n),n是field总数
hsetnx key field valueO(1)
hincrby key field incrementO(1)
hincrbyfloat key field incrementO(1)
hstrlen key fieldO(1)

哈希类型典型使用场景

在日常开发中,如果我们要缓存某行用户信息,那么使用哈希类型存储非常合适不过了。
在这里插入图片描述
使用哈希类型缓存信息主要有以下原因

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

但是需要注意的是哈希存储相对二维表更加稀疏,如上图,二维表中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 valueO(n),n是pivot 距离列表头或尾的距离
lrange key start endo(s+n),s是start偏移量,n是start到end的范围
lindex key indexO(n),n是索引的偏移量
llen keyO(1)
lpop keyO(1)
rpop keyO(1)
lrem count valueO(n),n是field总数
ltrim key start endO(n),n是要裁剪的元素总数
lset key index valueO(n),n是索引的偏移量
blpop brpopO(1)

列表类型典型使用场景

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

  • 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 keyO(1)
scard keyO(1)
sismember key elementO(1)
srandmember key [count]O(count)
spop keyO(1)
smembers keyO(n) ,n是元素总数
sinter key [key …]或者 sinterstoreO(m*k),k是多个集合中元素最少的个数,m是键个数
sunion key [key …]或者 sunionstoreO(k),k是多个集合元素个数和
sdiff key [key …]或者 sdiffstoreO(k),k是多个集合元素个数和

集合类型典型使用场景

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

有序集合类型常见命令

与集合差不多,相比集合多了score属性,使得集合有序,且它保留了集合的不可重复元素,但score是可重复的。
有序集合结构示意图

添加操作

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 withscores1) "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 keyO(1)
zscore key memberO(1)
zrank key member
zrevrank key member
O(log(n)),n 是当前有序集合成员个数
zrem key member [member …]O(k*log(n)),是删除成员的个数,n是当前有序集合成员个数
zincrby key increment memberO(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是当前有序集合成员个数
zcountO(log(n)),n 是当前有序集合成员个数
zremrengebyrank key start endO(log(n)+k),k是要删除的成员个数,n是当前有序集合成员个数
zremrangebyscore key min maxO(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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/667763.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java后端面试总结

Java语言具有哪些特点? Java为纯面向对象的语言。它能够直接反应现实生活中的对象。 具有平台无关性。java利用Java虚拟机运行字节码,无论是在Windows、Linux还是MacOS等其它平台对Java程序进行编译,编译后的程序可在其它平台运行。 Java为解释型语言,编译器把Java代码编译…

随机图论基础

一&#xff0c;随机图、随机图空间 1&#xff0c;随机图 一个n个点的无向图&#xff0c;最多有sn(n-1)/2条边。 每条边都有一定的概率存在&#xff0c;有一定概率不存在&#xff0c;那么每个图都有一个出现概率。 2&#xff0c;随机图空间 一共有2^s种不同的图&#xff0c…

[word] word怎么让字在横线上居中 #学习方法#媒体#媒体

word怎么让字在横线上居中 word怎么让字在横线上居中&#xff1f; 在word文档中&#xff0c;有时为了某些字句突出显示&#xff0c;需要用下划线来表示&#xff0c;当着重显示部分为金额、面积或某些选项时&#xff0c;需要一条长下划线上左右有空白&#xff0c;而文字在下划…

Linux下对线程的理解(上)

1、线程的概念 要理解线程首先要理解页表和进程地址空间&#xff0c;我是这样子理解的&#xff0c;1、进程地址空间是进程访问资源的窗口。2、页表是规定进程地址空间中哪些属于进程。3、合理的使用进程地址空间页表可以对资源进行划分。而如何理解进程呢&#xff1f;进程是接受…

算法题目题单——图论

简介 本文为自己做的一部分图论题目&#xff0c;作为题单列出&#xff0c;持续更新。 题单由题目链接和题解两部分组成&#xff0c;题解部分提供简洁题意&#xff0c;代码仓库&#xff1a;Kaiser-Yang/OJProblems。 对于同一个一级标题下的题目&#xff0c;题目难度尽可能做…

【vscode】windows11在vscode终端控制台中打印console.log()出现中文乱码问题解决

1. 问题描述 在前端开发过程中使用vscode编写node.js&#xff0c;需要在控制台中打印一些中文信息&#xff0c;但是一直出现中文乱码问题&#xff0c;英文和数字都显示正常。在网上试了很多设置的办法&#xff0c;最终找到windos11设置中解决。 2. 原因 首先打开控制台&…

centos 7.7 离线安装docker

centos 7.7 离线安装docker Index of linux/static/stable/x86_64/https://download.docker.com/linux/static/stable/x86_64/ 【1】离线下载docker 压缩包上传至 /usr/local 目录&#xff0c;解压缩&#xff0c;并复制到 /usr/bin/ 目录中。 cd /usr/local/tar -zxvf docke…

力扣 第 123 场双周赛 解题报告 | 珂学家 | 二维偏序+单调队列优化

前言 执手看歌敲金钗&#xff0c;笑语落珠明眸睐。 忽然蝴蝶春风满&#xff0c;焉教冷镜瘦朱颜。 整体评价 T3是基于map的前缀和的变形题&#xff0c;T4是二维偏序的一道应用题。 题外话&#xff0c;力扣还是实现N久之前的承诺了&#xff0c;命名权奖励&#xff0c;赞一个。 …

7隐藏进程_Linux_Rootkit.md

Xcellerator 密码学Linux其他逆向工程 文章目录 [Linux Rootkit 第 7 部分&#xff1a;隐藏进程](https://xcellerator.github.io/posts/linux_rootkits_07/)选择要隐藏的 PID隐藏 PID Linux Rootkit 第 7 部分&#xff1a;隐藏进程 2020-10-01 :: TheXcellerator # linux #…

Python调用pyspark报错整理

前言 Pycharm配置了SSH服务器和Anaconda的python解释器&#xff0c;如果没有配置可参考 大数据单机学习环境搭建(8)Linux单节点Anaconda安装和Pycharm连接 Pycharm执行的脚本 执行如下 pyspark_model.py 的python脚本&#xff0c;构建SparkSession来执行sparksql "&qu…

学习的数据结构和算法第2天

数据结构 ​ 是计算机储存、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的数据元素 利用一些方式实现一些项目在内存中奖数据存储起来。 1、数组 2、链表 3、树 算法 ​ 就是定义良好的计算过程&#xff0c;它取一个或一组的值为输入&#xff0c;并…

Quartus IP 之mif与hex文件创建与使用

一、mif与hex概述 ROM IP的数据需要满足断电不丢失的要求&#xff0c;ROM IP数据的文件格式一般有三种文件格式&#xff1a;.mif、.hex、.coe&#xff0c;Xilinx与Intel Altera支持的ROM IP数据文件格式如下&#xff1a; Xilinx与Altera支持的ROM文件格式 Alterahex、mifAM&am…

pwn学习笔记(2)

pwn学习笔记&#xff08;2&#xff09; 1.三种常见的寄存器&#xff1a; ​ ax寄存器&#xff1a;通用寄存器&#xff0c;可用于存放多种数据 ​ bp寄存器&#xff1a;存放的是栈帧的栈底地址 ​ sp寄存器&#xff1a;存放的是栈顶的地址 2.栈帧与栈工作的简介&#xff1a…

Objective-C 中的SEL

在 Objective-C 中&#xff0c;SEL&#xff08;Selector&#xff09;是一种用来表示方法的类型。 它实际上是一个指向方法的指针&#xff0c;用于在运行时动态调用方法。 下面是一个使用 SEL 的代码示例&#xff1a; #import <Foundation/Foundation.h>interface MyCl…

SplitFed: When Federated Learning Meets Split Learning

论文链接&#xff1a; [2004.12088v1] SplitFed: When Federated Learning Meets Split Learning (arxiv.org) AAAI 2022 摘要&#xff1a; 联邦学习分割学习&#xff1a;消除其固有的缺点的两种方法&#xff0c;以及结合差分隐私和PixelDP的精细架构配置&#xff0c;以增强…

CSS transition的一些见解

CSSTransition是CSS3中新添加的特性&#xff0c;可以用来创建元素的过渡效果。当元素在大小、颜色、布局、透明度等数值改变时&#xff0c;可以使其产生过渡的动画效果。 CSSTransition的主要属性包括&#xff1a; transition-property&#xff1a;指定当元素哪个属性改变时执…

【Spring连载】使用Spring Data访问Redis(十)----Lua脚本支持Scripting

【Spring连载】使用Spring Data访问Redis&#xff08;十&#xff09;----Lua脚本支持Scripting Redis 2.6及更高版本支持通过eval 和 evalsha 命令运行Lua脚本。Spring Data Redis为运行处理序列化的脚本提供了高级抽象&#xff0c;并自动使用Redis脚本缓存。 脚本可以通过调用…

云计算关键技术

目录 一、云计算关键技术概述 1.1 概述 二、关键技术内容 2.1 虚拟化技术 2.2 分布式数据存储技术 2.3 资源管理技术 2.4 云计算平台管理技术 2.5 多租户隔离技术 2.5.1 多租户技术下SaaS 特征 2.5.2 多租户技术面临的技术难题 2.5.2.1 数据隔离 2.5.2.2 客户化配置…

Can调试工具源码

Can调试工具源码 CANTool通用测试软件是一个专门用来socket can接口进行测试的软件工具&#xff0c;此软件操作简单&#xff0c;容易上手&#xff0c;通过运用此软件可以非常方便的对linux系统的can接口进行测试&#xff0c;从而熟悉can接口的使用方法&#xff0c;并且此为源码…

C# CAD界面-自定义工具栏(三)

运行环境 vs2022 c# cad2016 调试成功 一、引用 二、开发代码进行详细的说明 初始化与获取AutoCAD核心对象&#xff1a; Database db HostApplicationServices.WorkingDatabase;&#xff1a;这行代码获取当前工作中的AutoCAD数据库对象。在AutoCAD中&#xff0c;所有图形数…