Redis常用数据结构有哪些及怎么实现

48次阅读
没有评论

共计 7607 个字符,预计需要花费 20 分钟才能阅读完成。

这篇文章主要介绍“Redis 常用数据结构有哪些及怎么实现”,在日常操作中,相信很多人在 Redis 常用数据结构有哪些及怎么实现问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Redis 常用数据结构有哪些及怎么实现”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!

Redis 常用数据结构

Redis 提供了一些数据结构供我们往 Redis 中存取数据,最常用的的有 5 种,字符串(String)、哈希(Hash)、列表(list)、集合(set)、有序集合(ZSET)。

字符串(String)

字符串类型是 Redis 最基础的数据结构。首先键都是字符串类型,而且其他几种数据结构都是在字符串类型基础上构建的,所以字符串类型能为其他四种数据结构的学习奠定基础。字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串(例如 JSON、XML))、数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过 512MB。

(虽然 Redis 是 C 写的,C 里面有字符串 本质使用 char 数组来实现,但是处于种种考虑,Redis 还是自己实现了字符串类型)

操作命令 set 设置值

set key value

set 命令有几个选项:

ex seconds: 为键设置秒级过期时间。

px milliseconds: 为键设置毫秒级过期时间。

nx: 键必须不存在, 才可以设置成功,用于添加(分布式锁常用)。

xx: 与 nx 相反, 键必须存在,才可以设置成功, 用于更新。

从执行效果上看,ex 参数和 expire 命令基本一样。还有一个需要特别注意的地方是如果一个字符串已经设置了过期时间,然后你调用了 set 方法修改了它,它的过期时间会消失。

而 nx 和 xx 执行效果如下

除了 set 选项,Redis 还提供了 setex 和 setnx 两个命令:

setex key
seconds value

setnx key value

setex 和 setnx 的作用和 ex 和 nx 选项是一样的。也就是,setex 为键设置秒级过期时间,setnx 设置时键必须不存在, 才可以设置成功。

setex 示例:

setnx 示例:

因为键 foo-ex 已存在, 所以 setnx 失败, 返回结果为 0,键 foo-ex2 不存在,所以 setnx 成功, 返回结果为 1。

有什么应用场景吗? 以 setnx 命令为例子,由于 Redis 的单线程命令处理机制,如果有多个客户端同时执行 setnx key value,根据 setnx 的特性只有一个客户端能设置成功,setnx 可以作为分布式锁的一种实现方案。当然分布式锁没有不是只有一个命令就 OK 了,其中还有很多的东西要注意,我们后面会用单独的章节来讲述基于 Redis 的分布式锁。

get 获取值

如果要获取的键不存在, 则返回 nil(空):

mset 批量设置值

通过 mset 命令一次性设置 4 个键值对

mget 批量获取值

批量获取了键 a、b、c、d 的值:

如果有些键不存在, 那么它的值为 nil(空),结果是按照传入键的顺序返回。

批量操作命令可以有效提高效率,假如没有 mget 这样的命令,要执行 n 次 get 命令具体耗时如下:

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

使用 mget 命令后,要执行 n 次 get 命令操作具体耗时如下:

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

Redis 可以支撑每秒数万的读写操作,但是这指的是 Redis 服务端的处理能力,对于客户端来说,一次命令除了命令时间还是有网络时间,假设网络时间为 1 毫秒,命令时间为 0.1 毫秒(按照每秒处理 1 万条命令算),那么执行 1000 次 get 命令需要 1.1 秒(10001+10000.1=1100ms),1 次 mget 命令的需要 0.101 秒(11+10000.1=101ms)。

Incr 数字运算

incr 命令用于对值做自增操作, 返回结果分为三种情况:

值不是整数, 返回错误。

值是整数,返回自增后的结果。

键不存在,按照值为 0 自增, 返回结果为 1。

除了 incr 命令,Redis 提供了 decr(自减)、incrby(自增指定数字)、decrby(自减指定数字)、incrbyfloat(自增浮点数),具体效果请同学们自行尝试。

append 追加指令

append 可以向字符串尾部追加值

strlen 字符串长度

返回字符串长度

Redis 常用数据结构有哪些及怎么实现

注意:每个中文占 3 个字节

getset 设置并返回原值

getset 和 set 一样会设置值, 但是不同的是,它同时会返回键原来的值

Redis 常用数据结构有哪些及怎么实现

setrange 设置指定位置的字符

Redis 常用数据结构有哪些及怎么实现

下标从 0 开始计算。

getrange 截取字符串

getrange 截取字符串中的一部分,形成一个子串,需要指明开始和结束的偏移量,截取的范围是个闭区间。

Redis 常用数据结构有哪些及怎么实现

命令的时间复杂度

字符串这些命令中,除了 del、mset、mget 支持多个键的批量操作,时间复杂度和键的个数相关,为 O(n),getrange 和字符串长度相关,也是 O(n),其余的命令基本上都是 O(1)的时间复杂度,在速度上还是非常快的。

使用场景

字符串类型的使用场景很广泛:

缓存功能

Redis 作为缓存层,MySQL 作为存储层,绝大部分请求的数据都是从 Redis 中获取。由于 Redis 具有支撑高并发的特性, 所以缓存通常能起到加速读写和降低后端压力的作用。

计数

使用 Redis 作为计数的基础工具,它可以实现快速计数、查询缓存的功能, 同时数据可以异步落地到其他数据源。

共享 Session

一个分布式 Web 服务将用户的 Session 信息(例如用户登录信息)保存在各自服务器中,这样会造成一个问题,出于负载均衡的考虑,分布式服务会将用户的访问均衡到不同服务器上,用户刷新一次访问可能会发现需要重新登录,这个问题是用户无法容忍的。

为了解决这个问题, 可以使用 Redis 将用户的 Session 进行集中管理,,在这种模式下只要保证 Redis 是高可用和扩展性的, 每次用户更新或者查询登录信息都直接从 Redis 中集中获取。

限速

比如,很多应用出于安全的考虑, 会在每次进行登录时, 让用户输入手机验证码, 从而确定是否是用户本人。但是为了短信接口不被频繁访问, 会限制用户每分钟获取验证码的频率,例如一分钟不能超过 5 次。一些网站限制一个 IP 地址不能在一秒钟之内方问超过 n 次也可以采用类似的思路。

哈希(Hash)

Java 里提供了 HashMap,Redis 中也有类似的数据结构,就是哈希类型。但是要注意,哈希类型中的映射关系叫作 field-value,注意这里的 value 是指 field 对应的值,不是键对应的值。

操作命令

基本上,哈希的操作命令和字符串的操作命令很类似,很多命令在字符串类型的命令前面加上了 h 字母,代表是操作哈希类型,同时还要指明要操作的 field 的值。

hset 设值

hset user:1 name lijin

Redis 常用数据结构有哪些及怎么实现

如果设置成功会返回 1,反之会返回 0。此外 Redis 提供了 hsetnx 命令,它们的关系就像 set 和 setnx 命令一样, 只不过作用域由键变为 field。

hget 取值

hget user:1 name

如果键或 field 不存在,会返回 nil。

Redis 常用数据结构有哪些及怎么实现

hdel 删除 field

hdel 会删除一个或多个 field,返回结果为成功删除 field 的个数。

Redis 常用数据结构有哪些及怎么实现

hlen 计算 field 个数

Redis 常用数据结构有哪些及怎么实现

hmset 批量设值

Redis 常用数据结构有哪些及怎么实现

hmget 批量取值

Redis 常用数据结构有哪些及怎么实现

hexists 判断 field 是否存在

Redis 常用数据结构有哪些及怎么实现

若存在返回 1,不存在返回 0

hkeys 获取所有 field

它返回指定哈希键所有的 field

Redis 常用数据结构有哪些及怎么实现

hvals 获取所有 value

Redis 常用数据结构有哪些及怎么实现

hgetall 获取所有 field 与 value

Redis 常用数据结构有哪些及怎么实现

在使用 hgetall 时,如果哈希元素个数比较多,会存在阻塞 Redis 的可能。如果只需要获取部分 field,可以使用 hmget,如果一定要获取全部 field-value,可以使用 hscan 命令,该命令会渐进式遍历哈希类型,hscan 将在后面的章节介绍。

hincrby 增加

hincrby 和 hincrbyfloat,就像 incrby 和 incrbyfloat 命令一样,但是它们的作用域是 filed。

hstrlen 计算 value 的字符串长度

Redis 常用数据结构有哪些及怎么实现

命令的时间复杂度

哈希类型的操作命令中,hdel,hmget,hmset 的时间复杂度和命令所带的 field 的个数相关 O(k),hkeys,hgetall,hvals 和存储的 field 的总数相关,O(N)。其余的命令时间复杂度都是 O(1)。

使用场景

从前面的操作可以看出,String 和 Hash 的操作非常类似,那为什么要弄一个 hash 出来存储。

哈希类型比较适宜存放对象类型的数据,我们可以比较下,如果数据库中表记录 user 为:

idnameage1lijin182msb20

1、使用 String 类型

需要一条条去插入获取。

set user:1:name lijin;

set user:1:age  18;

set user:2:name msb;

set user:2:age  20;

优点:简单直观,每个键对应一个值

缺点:键数过多,占用内存多,用户信息过于分散,不用于生产环境

2、将对象序列化存入 redis

set user:1 serialize(userInfo);

优点:编程简单,若使用序列化合理内存使用率高

缺点:序列化与反序列化有一定开销,更新属性时需要把 userInfo 全取出来进行反序列化,更新后再序列化到 redis

3、使用 hash 类型

hmset user:1 name lijin age 18

hmset user:2 name msb age 20

优点:简单直观,使用合理可减少内存空间消耗

缺点:要控制内部编码格式,不恰当的格式会消耗更多内存

列表(list)

列表 (list) 类型是用来存储多个有序的字符串,a、b、c、c、b 四个元素从左到右组成了一个有序的列表, 列表中的每个字符串称为元素 (element),一个列表最多可以存储(2^32-1) 个元素(4294967295)。

Redis 常用数据结构有哪些及怎么实现

在 Redis 中,可以对列表两端插入 (push) 和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等。列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。

列表类型有两个特点:

第一、列表中的元素是有序的,这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表。

第二、列表中的元素可以是重复的。

操作命令 lrange 获取指定范围内的元素列表(不会删除元素)

key start end

索引下标特点:从左到右为 0 到 N -1

lrange 0 - 1 命令可以从左到右获取列表的所有元素

rpush 向右插入

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

lpush 向左插入

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

linsert 在某个元素前或后插入新元素

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

这三个返回结果为命令完成后当前列表的长度,也就是列表中包含的元素个数,同时 rpush 和 lpush 都支持同时插入多个元素。

lpop 从列表左侧弹出(会删除元素)

Redis 常用数据结构有哪些及怎么实现r

请注意,弹出来元素就没了。

rpop 从列表右侧弹出

rpop 将会把列表最右侧的元素 d 弹出。

Redis 常用数据结构有哪些及怎么实现

lrem 对指定元素进行删除

Redis 常用数据结构有哪些及怎么实现

lrem 命令会从列表中找到等于 value 的元素进行删除,根据 count 的不同分为三种情况:

count 0,从左到右, 删除最多 count 个元素。

count 0,从右到左, 删除最多 count 绝对值个元素。

count=0,删除所有。

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

返回值是实际删除元素的个数。

ltirm 按照索引范围修剪列表

例如想保留列表中第 0 个到第 1 个元素

Redis 常用数据结构有哪些及怎么实现ls

lset 修改指定索引下标的元素

Redis 常用数据结构有哪些及怎么实现

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

Redis 常用数据结构有哪些及怎么实现l

llen 获取列表长度

Redis 常用数据结构有哪些及怎么实现

blpop 和 brpop 阻塞式弹出元素

blpop 和 brpop 是 lpop 和 rpop 的阻塞版本,除此之外还支持多个列表类型,也支持设定阻塞时间,单位秒,如果阻塞时间为 0,表示一直阻塞下去。我们以 brpop 为例说明。

Redis 常用数据结构有哪些及怎么实现

A 客户端阻塞了(因为没有元素就会阻塞)

Redis 常用数据结构有哪些及怎么实现

A 客户端一直处于阻塞状态。此时我们从另一个客户端 B 执行

Redis 常用数据结构有哪些及怎么实现

A 客户端则输出

Redis 常用数据结构有哪些及怎么实现

注意:brpop 后面如果是多个键,那么 brpop 会从左至右遍历键,一旦有一个键能弹出元素,客户端立即返回。

使用场景

列表类型可以用于比如:

消息队列,Redis 的 lpush+brpop 命令组合即可实现阻塞队列,生产者客户端使用 lrpush 从列表左侧插入元素,多个消费者客户端使用 brpop 命令阻塞式的“抢”列表尾部的元素, 多个客户端保证了消费的负载均衡和高可用性。

文章列表

每个用户有属于自己的文章列表,现需要分页展示文章列表。此时可以考虑使用列表, 因为列表不但是有序的, 同时支持按照索引范围获取元素。

实现其他数据结构

lpush+lpop =Stack(栈)

lpush +rpop =Queue(队列)

lpsh+ ltrim =Capped Collection(有限集合)

lpush+brpop=Message Queue(消息队列)

集合(set)

Redis 常用数据结构有哪些及怎么实现

集合(set)类型也是用来保存多个的字符串元素, 但和列表类型不一样的是,集合中不允许有重复元素, 并且集合中的元素是无序的, 不能通过索引下标获取元素。

一个集合最多可以存储 2 的 32 次方 - 1 个元素。Redis 除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,合理地使用好集合类型, 能在实际开发中解决很多实际问题。

集合内操作命令 sadd 添加元素

允许添加多个,返回结果为添加成功的元素个数

Redis 常用数据结构有哪些及怎么实现

srem 删除元素

允许删除多个,返回结果为成功删除元素个数

Redis 常用数据结构有哪些及怎么实现

scard 计算元素个数

Redis 常用数据结构有哪些及怎么实现

sismember 判断元素是否在集合中

如果给定元素 element 在集合内返回 1,反之返回 0

Redis 常用数据结构有哪些及怎么实现

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

指定个数如果不写默认为 1

Redis 常用数据结构有哪些及怎么实现

spop 从集合随机弹出元素

同样可以指定个数,如果不写默认为 1,注意,既然是弹出,spop 命令执行后, 元素会从集合中删除, 而 srandmember 不会。

Redis 常用数据结构有哪些及怎么实现

smembers 获取所有元素(不会弹出元素)

返回结果是无序的

Redis 常用数据结构有哪些及怎么实现

集合间操作命令

现在有两个集合, 它们分别是 set1 和 set2

Redis 常用数据结构有哪些及怎么实现

sinter 求多个集合的交集

Redis 常用数据结构有哪些及怎么实现

suinon 求多个集合的并集

Redis 常用数据结构有哪些及怎么实现

sdiff 求多个集合的差集

Redis 常用数据结构有哪些及怎么实现

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

sinterstore destination key [key ...]
suionstore destination key [key ...]
sdiffstore destination key [key ...]复制代码

集合间的运算在元素较多的情况下会比较耗时,所以 Redis 提供了上面三个命令 (原命令 +store) 将集合间交集、并集、差集的结果保存在 destination key 中,例如:

Redis 常用数据结构有哪些及怎么实现

使用场景

集合类型比较典型的使用场景是标签(tag)。例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。有了这些数据就可以得到喜欢同一个标签的人,以及用户的共同喜好的标签,这些数据对于用户体验以及增强用户黏度比较重要。

例如一个电子商务的网站会对不同标签的用户做不同类型的推荐,比如对数码产品比较感兴趣的人,在各个页面或者通过邮件的形式给他们推荐最新的数码产品,通常会为网站带来更多的利益。

除此之外,集合还可以通过生成随机数进行比如抽奖活动,以及社交图谱等等。

有序集合(ZSET)

Redis 常用数据结构有哪些及怎么实现

有序集合相对于哈希、列表、集合来说会有一点点陌生, 但既然叫有序集合, 那么它和集合必然有着联系, 它保留了集合不能有重复成员的特性, 但不同的是, 有序集合中的元素可以排序。但是它和列表使用索引下标作为排序依据不同的是, 它给每个元素设置一个分数 (score) 作为排序的依据。

有序集合中的元素不能重复,但是 score 可以重复,就和一个班里的同学学号不能重复, 但是考试成绩可以相同。

有序集合提供了获取指定分数和元素范围查询、计算成员排名等功能,合理的利用有序集合,能帮助我们在实际开发中解决很多问题。

集合内操作命令 zadd 添加成员

Redis 常用数据结构有哪些及怎么实现

返回结果代表成功添加成员的个数

要注意:

Redis 常用数据结构有哪些及怎么实现

zadd 命令还有四个选项 nx、xx、ch、incr 四个选项

nx: member 必须不存在,才可以设置成功,用于添加。

xx: member 必须存在,才可以设置成功, 用于更新。

ch: 返回此次操作后, 有序集合元素和分数发生变化的个数

incr: 对 score 做增加,相当于后面介绍的 zincrby

zcard 计算成员个数

Redis 常用数据结构有哪些及怎么实现

zscore 计算某个成员的分数

Redis 常用数据结构有哪些及怎么实现

如果成员不存在则返回 nil

zrank 计算成员的排名

Redis 常用数据结构有哪些及怎么实现

zrank 是从分数从低到高返回排名

zrevrank 反之

很明显,排名从 0 开始计算。

zrem 删除成员

Redis 常用数据结构有哪些及怎么实现

允许一次删除多个成员。

返回结果为成功删除的个数。

zincrby 增加成员的分数

Redis 常用数据结构有哪些及怎么实现

zrange 和 zrevrange 返回指定排名范围的成员

有序集合是按照分值排名的,zrange 是从低到高返回,zrevrange 反之。如果加上
withscores 选项,同时会返回成员的分数

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

zrangebyscore 返回指定分数范围的成员

zrangebyscore key min max [withscores] [limit offset count]
zrevrangebyscore key max min [withscores][limit offset count]复制代码

其中 zrangebyscore 按照分数从低到高返回,zrevrangebyscore 反之。例如下面操作从低到高返回 200 到 221 分的成员,withscores 选项会同时返回每个成员的分数。

同时 min 和 max 还支持开区间(小括号)和闭区间(中括号),-inf 和 +inf 分别代表无限小和无限大:

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

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

zcount key min max

Redis 常用数据结构有哪些及怎么实现

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

zremrangebyrank key start end

zremrangebyscore 删除指定分数范围的成员

zremrangebyscore key min max

集合间操作命令 zinterstore 交集

zinterstoreRedis 常用数据结构有哪些及怎么实现

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

destination: 交集计算结果保存到这个键。

numkeys: 需要做交集计算键的个数。

key [key …]: 需要做交集计算的键。

weights weight
[weight …]: 每个键的权重,在做交集计算时,每个键中的每个 member 会将自己分数乘以这个权重, 每个键的权重默认是 1。

aggregate sum/
min |max: 计算成员交集后,分值可以按照 sum(和)、min(最小值)、max(最大值)做汇总, 默认值是 sum。

不太好理解,我们用一个例子来说明。(算平均分)

Redis 常用数据结构有哪些及怎么实现

Redis 常用数据结构有哪些及怎么实现

zunionstore 并集

该命令的所有参数和 zinterstore 是一致的,只不过是做并集计算,大家可以自行实验。

到此,关于“Redis 常用数据结构有哪些及怎么实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-13发表,共计7607字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)