当前位置: 首页 > news >正文

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/

相关文章:

Redis之基础篇

Redis简介 Redis是一种基于键值对&#xff08;Key-Value&#xff09;的NoSQL数据库&#xff0c;它支持string&#xff08;字符串&#xff09;、hash&#xff08;哈希&#xff09;、list&#xff08;列表&#xff09;、set&#xff08;集合&#xff09;、zset&#xff08;有序集…...

靶机实战bwapp亲测xxe漏洞攻击及自动化XXE注射工具分析利用

靶机实战bwapp亲测xxe漏洞攻击及自动化XXE注射工具分析利用。 1|0介绍 xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤,从而可以造成命令执行,目录遍历等.首先存在漏洞的web服务一定是存在xml传输数据的,可以在http头的content-type中查…...

openGauss学习笔记-216 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-CPU

文章目录 openGauss学习笔记-216 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-CPU216.1 CPU216.2 查看CPU状况216.3 性能参数分析 openGauss学习笔记-216 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-CPU 获取openGauss节点的CPU、内存、I/O和网络资源使用情况…...

【教程】Linux使用git自动备份和使用支持文件恢复的rm命令

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 背景介绍 首先非常不幸地告诉你&#xff1a;Linux 系统的标准 rm 命令不支持文件恢复功能。一旦使用 rm 删除了文件或目录&#xff0c;它们就会从文件系统中永久删除&#xff0c;除非你使用专门的文件恢复工具尝试…...

记录使用M1 Mac开发LVGL嵌入式项目

技术流 使用Gui Guider进行UI设计&#xff0c;生成lvgl code将lvgl code移植到esp32s3开发板 Gui Guider的安装 安装下面流程一步一步进行 LVGL的移植 硬件&#xff1a;esp32-8048s043开发板 开发环境&#xff1a;PlatformIO M1芯片安装ESP32驱动 从https://www.wch.cn…...

【SpringBoot】JWT令牌

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;SpringBoot ⛺️稳重求进&#xff0c;晒太阳 什么是JWT JWT简称JSON Web Token&#xff0c;也就是通过JSON形式作为Web应用的令牌&#xff0c;用于各方面之间安全的将信息作为JSON对象传输…...

Python爬虫 Beautiful Soup库详解#4

爬虫专栏&#xff1a;http://t.csdnimg.cn/WfCSx 使用 Beautiful Soup 前面介绍了正则表达式的相关用法&#xff0c;但是一旦正则表达式写的有问题&#xff0c;得到的可能就不是我们想要的结果了。而且对于一个网页来说&#xff0c;都有一定的特殊结构和层级关系&#xff0c;…...

Tkinter教程21:Listbox列表框+OptionMenu选项菜单+Combobox下拉列表框控件的使用+绑定事件

------------★Tkinter系列教程★------------ Tkinter教程21&#xff1a;Listbox列表框OptionMenu选项菜单Combobox下拉列表框控件的使用绑定事件 Tkinter教程20&#xff1a;treeview树视图组件&#xff0c;表格数据的插入与表头排序 Python教程57&#xff1a;tkinter中如何…...

Django中的SQL注入攻击防御策略

Django中的SQL注入攻击防御策略 SQL注入是一种常见的网络安全威胁&#xff0c;可以导致数据库被非法访问和数据泄露。本文将介绍在Django框架中防止SQL注入攻击的关键方法&#xff0c;包括使用参数化查询、使用ORM、进行输入验证和使用安全的编码实践。 SQL注入是一种利用应用程…...

ORM模型类

模型 创建两个表 创建模型类 from django.db import models# Create your models here. class BookInfo(models.Model):name models.CharField(max_length10, uniqueTrue) # 书名pub_date models.DateField(nullTrue) # 发布时间read_count models.IntegerField(default…...

Java强训day14(选择题编程题)

选择题 编程题 题目1 import java.util.Scanner;public class Main {public static void main(String[] args) {//读入年月日&#xff08;字符串形式读入&#xff09;Scanner sc new Scanner(System.in);String s sc.nextLine();String[] ss s.split(" ");i…...

Redis核心技术与实战【学习笔记】 - 31.番外篇:Redis客户端如何与服务器端交换命令和数据

简述 Redis 使用 RESP 协议&#xff08;Redis Serialzation Protocol&#xff09;协议定义了客户端和服务器端交互的命令、数据的编码格式。在 Redis 2.0 版本中&#xff0c;RESP 协议正式称为客户端和服务器端的标准通信协议。从 Redis 2.0 到 Redis 5.0 &#xff0c;RESP 协…...

电缆线的阻抗50Ω,真正含义是什么?

当我们提到电缆线的阻抗时&#xff0c;它到底是什么意思&#xff1f;RG58电缆通常指的是50Ω的电缆线。它的真正含义是什么&#xff1f;假如取一段3英尺(0.9144米)长的RG58电缆线&#xff0c;并且在前端测量信号路径与返回路径之间的阻抗。那么测得的阻抗是多少&#xff1f;当然…...

校园团餐SAAS系统源码

## 项目介绍 校园团餐SAAS系统&#xff0c;是全新推出的一款轻量级、高性能、前后端分离的团餐系统&#xff0c;支持微信小程序 。 技术特点 > * 前后端完全分离 (互不依赖 开发效率高) > * 采用PHP8 (强类型严格模式) > * ThinkPHP8.0&#xff08;轻量级PHP开发框…...

图数据库neo4j入门

neo4j 一、安装二、简单操作<一>、创建<二>、查询<三>、关系<四>、修改<五>、删除 三、常见报错<一>、默认的数据库密码是neo4j,打开浏览器http://localhost:7474登录不上,报错: Neo.ClientError.Security.Unauthorized: The client is un…...

Multisim14.0仿真(五十五)汽车转向灯设计

一、功能描述&#xff1a; 左转向&#xff1a;左侧指示灯循环依次闪亮&#xff1b; 右转向&#xff1a;右侧指示灯循环依次闪亮&#xff1b; 刹车&#xff1a; 所有灯常亮&#xff1b; 正常&#xff1a; 所有灯熄灭。 二、主要芯片&#xff1a; 74LS161D 74LS04D 74…...

2402C++,C++的反向代理

原文 cinatra支持反向代理很简单,5行代码就可以了.先看一个简单的示例: #include "cinatra/coro_http_reverse_proxy.hpp" using namespace cinatra; int main() {reverse_proxy proxy_rr(10, 8091);proxy_rr.add_dest_host("127.0.0.1:9001");proxy_rr.a…...

[职场] 服务行业个人简历 #笔记#笔记

服务行业个人简历 服务员个人简历范文1 姓名: XXX国籍:中国 目前所在地:天河区民族:汉族 户口所在地:阳江身材: 160cm43kg 婚姻状况:未婚年龄: 21岁 培训认证:诚信徽章: 求职意向及工作经历 人才类型:普通求职 应聘职位: 工作年限:职称:初级 求职类型:全职可到职日期:随时 月薪…...

代码随想录算法训练营|day30

第七章 回溯算法 332.重新安排行程51.N皇后37.解数独代码随想录文章详解 332.重新安排行程 (1)参考 创建map存储src&#xff0c;[]dest映射关系&#xff0c;并对[]dest排序 每次取map中第一个dest访问&#xff0c;将其作为新的src&#xff0c;每访问一条src->dest&#xff…...

PHPExcel导出excel

PHPExcel下载地址 https://gitee.com/mirrors/phpexcelhttps://github.com/PHPOffice/PHPExcel 下载后目录结构 需要的文件如下图所示 将上面的PHPExcel文件夹和PHPExcel.php复制到你需要的地方 这是一个简单的示例代码 <?php$dir dirname(__FILE__); //require_once …...

ubuntu系统下c++ cmakelist vscode debug(带传参的debug)的详细示例

c和cmake的debug&#xff0c;网上很多都需要配置launch.json&#xff0c;cpp.json啥的&#xff0c;记不住也太复杂了&#xff0c;我这里使用cmake插件带有的设置&#xff0c;各位可以看一看啊✌(不知不觉&#xff0c;竟然了解了vscode中配置文件的生效逻辑&#x1f923;) 克隆…...

聊聊JIT优化技术

&#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是小徐&#x1f947;☁️博客首页&#xff1a;CSDN主页小徐的博客&#x1f304;每日一句&#xff1a;好学而不勤非真好学者 &#x1f4dc; 欢迎大家关注&#xff01; ❤️ 我们知道&#xff0c;想要把高级语言转变成计算…...

LabVIEW动平衡测试与振动分析系统

LabVIEW动平衡测试与振动分析系统 介绍了利用LabVIEW软件和虚拟仪器技术开发一个动平衡测试与振动分析系统。该系统旨在提高旋转机械设备的测试精度和可靠性&#xff0c;通过精确测量和分析设备的振动数据&#xff0c;以识别和校正不平衡问题&#xff0c;从而保证机械设备的高…...

《低功耗方法学》翻译——附录B:UPF命令语法

附录B&#xff1a;UPF命令语法 本章介绍了文本中引用的所选UPF命令的语法。 节选自“统一电源格式&#xff08;UPF&#xff09;标准&#xff0c;1.0版”&#xff0c;经该Accellera许可复制。版权所有&#xff1a;(c)2006-2007。Accellera不声明或代表摘录材料的准确性或内容&…...

Leetcode 3027. Find the Number of Ways to Place People II

Leetcode 3027. Find the Number of Ways to Place People II 1. 解题思路2. 代码实现 题目链接&#xff1a;3027. Find the Number of Ways to Place People II 1. 解题思路 这一题的话我也没想到啥特别好的思路&#xff0c;采用的纯粹是遍历剪枝的思路。 遍历的话好理解&…...

android inset 管理

目录 简介 Insets管理架构 Insets相关类图 app侧的类 WMS侧的类 inset show的流程 接口 流程 WMS侧确定InsetsSourceControl的流程 两个问题 窗口显示时不改变现有的inset状态 全屏窗口上的dialog 不显示statusbar问题 View 和 DecorView 设置insets信息 输入法显…...

Python中使用opencv-python库进行颜色检测

Python中使用opencv-python库进行颜色检测 之前写过一篇VC中使用OpenCV进行颜色检测的博文&#xff0c;当然使用opencv-python库也可以实现。 在Python中使用opencv-python库进行颜色检测非常简单&#xff0c;首选读取一张彩色图像&#xff0c;并调用函数imgHSV cv2.cvtColor…...

如何修改远程端服务器密钥

前言 一段时间没改密码后&#xff0c;远程就会自动提示CtrlAltEnd键修改密码。但我电脑是笔记本&#xff0c;没有end键。打开屏幕键盘按这三个键也没用。 解决方法 打开远程 1、远程端WINC 输入osk 可以发现打开了屏幕键盘 2、电脑键盘同时按住CtrlAlt&#xff08;若自身电…...

lnmp指令

LNMP官网&#xff1a;https://lnmp.org 作者: licess adminlnmp.org 问题反馈&技术支持论坛&#xff1a;https://bbs.vpser.net/forum-25-1.html 打赏捐赠&#xff1a;https://lnmp.org/donation.html 自定义参数 lnmp.conf配置文件&#xff0c;可以修改lnmp.conf自定义下…...

Go语言每日一题——链表篇(七)

传送门 牛客面试笔试必刷101题 ----------------删除链表的倒数第n个节点 题目以及解析 题目 解题代码及解析 解析 这一道题与昨天的题目在解题思路上有一定的相似之处&#xff0c;都是基于双指针定义快慢指针&#xff0c;这里我们让快指针先走n步&#xff0c;又因为n一定…...

【stomp实战】websocket原理解析与简单使用

一、WebSocket 原理 WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术&#xff0c;属于应用层协议。它基于TCP传输协议&#xff0c;并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直接可以创建持久性的连接&#xff0c; 并…...

2024.1.30力扣每日一题——使循环数组所有元素相等的最少秒数

2024.1.30 题目来源我的题解方法一 暴力模拟&#xff08;无法通过&#xff09;方法二 哈希表数学 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2808 我的题解 方法一 暴力模拟&#xff08;无法通过&#xff09; 直接暴力枚举。记录每一个元素所在的位置&#xff0c;然…...

【Java万花筒】数据魔术师:探索Java商业智能与数据可视化

开发者的数据魔杖&#xff1a;掌握Java商业智能工具的秘诀 前言 在当今信息爆炸的时代&#xff0c;数据已经成为企业决策和业务发展的重要驱动力。为了更好地理解和利用数据&#xff0c;商业智能&#xff08;BI&#xff09;和数据可视化工具变得至关重要。本文将介绍几种基于…...

python用yaml装参数并支持命令行修改

效果&#xff1a; 将实验用的参数写入 yaml 文件&#xff0c;而不是全部用 argparse 传&#xff0c;否则命令会很长&#xff1b;同时支持在命令行临时加、改一些参数&#xff0c;避免事必要在 yaml 中改参数&#xff0c;比较灵活&#xff08;如 grid-search 时遍历不同的 loss…...

第59讲订单数据下拉实现

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;/*** 订单查询 type值 0 全部订单 1待付款 2 待收货 3 退款/退货* param type* return*/RequestMapping("/list")public R list(Integer type,Integer page,Integer pageSize){System.out.pri…...

[当人工智能遇上安全] 11.威胁情报实体识别 (2)基于BiGRU-CRF的中文实体识别万字详解

您或许知道&#xff0c;作者后续分享网络安全的文章会越来越少。但如果您想学习人工智能和安全结合的应用&#xff0c;您就有福利了&#xff0c;作者将重新打造一个《当人工智能遇上安全》系列博客&#xff0c;详细介绍人工智能与安全相关的论文、实践&#xff0c;并分享各种案…...

16:定时器和计数器

定时器和计数器 1、定时器和计数器的介绍2、定时器是如何工作3、寄存器4、51单片机定时器简介&#xff08;数据手册&#xff09;5、定时器中的寄存器&#xff08;数据手册&#xff09;5.1、TCON&#xff08;定时器控制寄存器&#xff09;5.2、TMOD&#xff08;工作模式寄存器&a…...

c#通过ExpressionTree 表达式树实现对象关系映射

//反射expression实现对象自动映射 void Main() {Person p1new(){Id1,Name"abc"};var persondto p1.MapTo<Person, PersonDto>();Console.WriteLine($"id:{persondto.Id}-name:{persondto.Name}"); }public static class AutoMapperExs { public s…...

《动手学深度学习(PyTorch版)》笔记7.2

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…...

【MySQL进阶之路】BufferPool 生产环境优化经验

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…...

Vim工具使用全攻略:从入门到精通

引言 在软件开发的世界里&#xff0c;Vim不仅仅是一个文本编辑器&#xff0c;它是一个让你的编程效率倍增的神器。然而&#xff0c;对于新手来说&#xff0c;Vim的学习曲线似乎有些陡峭。本文将手把手教你如何从Vim的新手逐渐变为高手&#xff0c;深入理解Vim的操作模式&#…...

Chapter 8 - 7. Congestion Management in TCP Storage Networks

TCP Flow Monitoring versus I/O Flow Monitoring TCP flow monitoring shouldn’t be confused with I/O flow monitoring because of the following reasons: TCP 流量监控不应与 I/O 流量监控混淆,原因如下: 1. TCP belongs to the transport layer (layer 4) of the OS…...

带你快速入门js高级-基础

1.作用域 全局 scriptxx.js 局部 函数作用域{} 块作用域 const let 2.闭包 函数外有权访问函数内的变量, 闭包可以延长变量生命周期 function 函数名 () {return function () {// 这里的变量不会立刻释放} }3.垃圾回收 不在使用(引用的变量), 防止占用内存&#xff0c;需要…...

数据结构与算法-链表(力扣附链接)

之前我们对C语言进行了一定的学习&#xff0c;有了一些基础之后&#xff0c;我们就可以学习一些比较基础的数据结构算法题了。这部分的知识对于我们编程的深入学习非常有用&#xff0c;对于一些基本的算法&#xff0c;我们学习之后&#xff0c;就可以参加一些编程比赛了&#x…...

多线程JUC:等待唤醒机制(生产者消费者模式)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;多线程&JUC&#xff1a;解决线程安全问题——synchronized同步代码块、Lock锁 &#x1f4da;订阅专栏&#xff1a;多线程&am…...

无人机动力系统高倍率锂聚合物电池介绍,无人机锂电池使用与保养,无人机飞行控制动力源详解

无人机电池使用及保养 电池是无人机飞行的动力来源,也是一个消耗品&#xff0c;对电池充分了解&#xff0c;采取正确的使用方法&#xff0c;妥善进行维护保养将有助于提高飞行的安全性、延长电池的使用寿命。以下将详细对电池的使用和管理进行讲解。 高倍率锂聚合物电池的含义…...

[BeginCTF]真龙之力

安装程序 双击安装 出现了安装失败的标签&#xff0c;开发者不允许测试。 查看Mainfest入口文件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android" android:versionCo…...

手写分布式存储系统v0.3版本

引言 承接 手写分布式存储系统v0.2版本 &#xff0c;今天开始新的迭代开发。主要实现 服务发现功能 一、什么是服务发现 由于咱们的服务是分布式的&#xff0c;那从服务管理的角度来看肯定是要有一个机制来知道具体都有哪些实例可以提供服务。举个例子就是&#xff0c;张三家…...

除夕快乐!

打印的简单实现&#xff0c;祝大家新的一年万事顺意&#xff01; 龙年大吉&#xff01; #include <stdio.h> #include <windows.h> #include <string.h>int main() {const char* message "除夕快乐!";int i;for (i 0; i < strlen(message);…...

17:定时器编程实战

1、实验目的 (1)使用定时器来完成LED闪烁 (2)原来实现闪烁时中间的延迟是用delay函数实现的&#xff0c;在delay的过程中CPU要一直耗在这里不能去做别的事情。这是之前的缺点 (3)本节用定时器来定一个时间&#xff08;譬如0.3s&#xff09;&#xff0c;在这个定时器定时时间内…...