首发于:Redis 5 种根本数据结构详解 - JavaGuide

相干文章:Redis常见面试题总结(上) 。

Redis 5 种根本数据结构(String、List、Hash、Set、Sorted Set)在面试中常常会被问到,这篇文章咱们一起来回顾复习一下。

还有几种比拟非凡的数据结构(HyperLogLogs、Bitmap 、Geospatial、Stream)也十分重要,咱们前面下次再聊!

上面是注释。

你能够在 Redis 官网上找到 Redis 数据结构十分具体的介绍:

  • Redis Data Structures
  • Redis Data types tutorial

将来随着 Redis 新版本的公布,可能会有新的数据结构呈现,通过查阅 Redis 官网对应的介绍,你总能获取到最靠谱的信息。

String(字符串)

介绍

String 是 Redis 中最简略同时也是最罕用的一个数据结构。

String 是一种二进制平安的数据结构,能够用来存储任何类型的数据比方字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的门路)、序列化后的对象。

尽管 Redis 是用 C 语言写的,然而 Redis 并没有应用 C 的字符串示意,而是本人构建了一种 简略动静字符串(Simple Dynamic String,SDS)。相比于 C 的原生字符串,Redis 的 SDS 不光能够保留文本数据还能够保留二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是平安的,不会造成缓冲区溢出。

常用命令

命令介绍
SET key value设置指定 key 的值
SETNX key value只有在 key 不存在时设置 key 的值
GET key获取指定 key 的值
MSET key1 value1 key2 value2 …设置一个或多个指定 key 的值
MGET key1 key2 ...获取一个或多个指定 key 的值
STRLEN key返回 key 所贮存的字符串值的长度
INCR key将 key 中贮存的数字值增一
DECR key将 key 中贮存的数字值减一
EXISTS key判断指定 key 是否存在
DEL key(通用)删除指定的 key
EXPIRE key seconds(通用)给指定 key 设置过期工夫

更多 Redis String 命令以及具体使用指南,请查看 Redis 官网对应的介绍:https://redis.io/commands/?gr... 。

基本操作

> SET key valueOK> GET key"value"> EXISTS key(integer) 1> STRLEN key(integer) 5> DEL key(integer) 1> GET key(nil)

批量设置

> MSET key1 value1 key2 value2OK> MGET key1 key2 # 批量获取多个 key 对应的 value1) "value1"2) "value2"

计数器(字符串的内容为整数的时候能够应用):

> SET number 1OK> INCR number # 将 key 中贮存的数字值增一(integer) 2> GET number"2"> DECR number # 将 key 中贮存的数字值减一(integer) 1> GET number"1"

设置过期工夫(默认为永不过期)

> EXPIRE key 60(integer) 1> SETNX key 60 value # 设置值并设置过期工夫OK> TTL key(integer) 56

利用场景

须要存储惯例数据的场景

  • 举例 :缓存 session、token、图片地址、序列化后的对象(相比拟于 Hash 存储更节俭内存)。
  • 相干命令 : SETGET

须要计数的场景

  • 举例 :用户单位工夫的申请数(简略限流能够用到)、页面单位工夫的拜访数。
  • 相干命令 :SETGETINCRDECR

分布式锁

利用 SETNX key value 命令能够实现一个最繁难的分布式锁(存在一些缺点,通常不倡议这样实现分布式锁)。

List(列表)

介绍

Redis 中的 List 其实就是链表数据结构的实现。我在 线性数据结构 :数组、链表、栈、队列 这篇文章中具体介绍了链表这种数据结构,我这里就不多做介绍了。

许多高级编程语言都内置了链表的实现比方 Java 中的 LinkedList,然而 C 语言并没有实现链表,所以 Redis 实现了本人的链表数据结构。Redis 的 List 的实现为一个 双向链表,即能够反对反向查找和遍历,更不便操作,不过带来了局部额定的内存开销。

常用命令

命令介绍
RPUSH key value1 value2 ...在指定列表的尾部(左边)增加一个或多个元素
LPUSH key value1 value2 ...在指定列表的头部(右边)增加一个或多个元素
LSET key index value将指定列表索引 index 地位的值设置为 value
LPOP key移除并获取指定列表的第一个元素(最右边)
RPOP key移除并获取指定列表的最初一个元素(最左边)
LLEN key获取列表元素数量
LRANGE key start end获取列表 start 和 end 之间 的元素

更多 Redis List 命令以及具体使用指南,请查看 Redis 官网对应的介绍:https://redis.io/commands/?gr... 。

通过 RPUSH/LPOP 或者 LPUSH/RPOP实现队列

> RPUSH myList value1(integer) 1> RPUSH myList value2 value3(integer) 3> LPOP myList"value1"> LRANGE myList 0 11) "value2"2) "value3"> LRANGE myList 0 -11) "value2"2) "value3"

通过 RPUSH/RPOP或者LPUSH/LPOP 实现栈

> RPUSH myList2 value1 value2 value3(integer) 3> RPOP myList2 # 将 list的头部(最左边)元素取出"value3"

我专门画了一个图不便大家了解 RPUSH , LPOP , lpush , RPOP 命令:

通过 LRANGE 查看对应下标范畴的列表元素

> RPUSH myList value1 value2 value3(integer) 3> LRANGE myList 0 11) "value1"2) "value2"> LRANGE myList 0 -11) "value1"2) "value2"3) "value3"

通过 LRANGE 命令,你能够基于 List 实现分页查问,性能十分高!

通过 LLEN 查看链表长度

> LLEN myList(integer) 3

利用场景

信息流展现

  • 举例 :最新文章、最新动静。
  • 相干命令 : LPUSHLRANGE

音讯队列

Redis List 数据结构能够用来做音讯队列,只是性能过于简略且存在很多缺点,不倡议这样做。

相对来说,Redis 5.0 新减少的一个数据结构 Stream 更适宜做音讯队列一些,只是性能仍然十分简陋。和业余的音讯队列相比,还是有很多欠缺的中央比方音讯失落和沉积问题不好解决。

Hash(哈希)

介绍

Redis 中的 Hash 是一个 String 类型的 field-value(键值对) 的映射表,特地适宜用于存储对象,后续操作的时候,你能够间接批改这个对象中的某些字段的值。

Hash 相似于 JDK1.8 前的 HashMap,外部实现也差不多(数组 + 链表)。不过,Redis 的 Hash 做了更多优化。

常用命令

命令介绍
HSET key field value设置指定哈希表中指定字段的值
HSETNX key field value只有指定字段不存在时设置指定字段的值
HMSET key field1 value1 field2 value2 ...同时将一个或多个 field-value (域-值)对设置到指定哈希表中
HGET key field获取指定哈希表中指定字段的值
HMGET key field1 field2 ...获取指定哈希表中一个或者多个指定字段的值
HGETALL key获取指定哈希表中所有的键值对
HEXISTS key field查看指定哈希表中指定的字段是否存在
HDEL key field1 field2 ...删除一个或多个哈希表字段
HLEN key获取指定哈希表中字段的数量

更多 Redis Hash 命令以及具体使用指南,请查看 Redis 官网对应的介绍:https://redis.io/commands/?gr... 。

模仿对象数据存储

> HMSET userInfoKey name "guide" description "dev" age "24"OK> HEXISTS userInfoKey name # 查看 key 对应的 value中指定的字段是否存在。(integer) 1> HGET userInfoKey name # 获取存储在哈希表中指定字段的值。"guide"> HGET userInfoKey age"24"> HGETALL userInfoKey # 获取在哈希表中指定 key 的所有字段和值1) "name"2) "guide"3) "description"4) "dev"5) "age"6) "24"> HSET userInfoKey name "GuideGeGe"> HGET userInfoKey name"GuideGeGe"

利用场景

对象数据存储场景

  • 举例 :用户信息、商品信息、文章信息、购物车信息。
  • 相干命令 :HSET (设置单个字段的值)、HMSET(设置多个字段的值)、HGET(获取单个字段的值)、HMGET(获取多个字段的值)。

Set(汇合)

介绍

Redis 中的 Set 类型是一种无序汇合,汇合中的元素没有先后顺序但都惟一,有点相似于 Java 中的 HashSet 。当你须要存储一个列表数据,又不心愿呈现反复数据时,Set 是一个很好的抉择,并且 Set 提供了判断某个元素是否在一个 Set 汇合内的重要接口,这个也是 List 所不能提供的。

你能够基于 Set 轻易实现交加、并集、差集的操作,比方你能够将一个用户所有的关注人存在一个汇合中,将其所有粉丝存在一个汇合。这样的话,Set 能够十分不便的实现如独特关注、独特粉丝、独特爱好等性能。这个过程也就是求交加的过程。

常用命令

命令介绍
SADD key member1 member2 ...向指定汇合增加一个或多个元素
SMEMBERS key获取指定汇合中的所有元素
SCARD key获取指定汇合的元素数量
SISMEMBER key member判断指定元素是否在指定汇合中
SINTER key1 key2 ...获取给定所有汇合的交加
SINTERSTORE destination key1 key2 ...将给定所有汇合的交加存储在 destination 中
SUNION key1 key2 ...获取给定所有汇合的并集
SUNIONSTORE destination key1 key2 ...将给定所有汇合的并集存储在 destination 中
SDIFF key1 key2 ...获取给定所有汇合的差集
SDIFFSTORE destination key1 key2 ...将给定所有汇合的差集存储在 destination 中
SPOP key count随机移除并获取指定汇合中一个或多个元素
SRANDMEMBER key count随机获取指定汇合中指定数量的元素

更多 Redis Set 命令以及具体使用指南,请查看 Redis 官网对应的介绍:https://redis.io/commands/?gr... 。

基本操作

> SADD mySet value1 value2(integer) 2> SADD mySet value1 # 不容许有反复元素,因而增加失败(integer) 0> SMEMBERS mySet1) "value1"2) "value2"> SCARD mySet(integer) 2> SISMEMBER mySet value1(integer) 1> SADD mySet2 value2 value3(integer) 2
  • mySet : value1value2
  • mySet2value2value3

求交加

> SINTERSTORE mySet3 mySet mySet2(integer) 1> SMEMBERS mySet31) "value2"

求并集

> SUNION mySet mySet21) "value3"2) "value2"3) "value1"

求差集

> SDIFF mySet mySet2 # 差集是由所有属于 mySet 但不属于 A 的元素组成的汇合1) "value1"

利用场景

须要寄存的数据不能反复的场景

  • 举例:网站 UV 统计(数据量微小的场景还是 HyperLogLog更适宜一些)、文章点赞、动静点赞等场景。
  • 相干命令:SCARD(获取汇合数量) 。

须要获取多个数据源交加、并集和差集的场景

  • 举例 :独特好友(交加)、独特粉丝(交加)、独特关注(交加)、好友举荐(差集)、音乐举荐(差集) 、订阅号举荐(差集+交加) 等场景。
  • 相干命令:SINTER(交加)、SINTERSTORE (交加)、SUNION (并集)、SUNIONSTORE(并集)、SDIFF(交加)、SDIFFSTORE (交加)。

须要随机获取数据源中的元素的场景

  • 举例 :抽奖零碎、随机。
  • 相干命令:SPOP(随机获取汇合中的元素并移除,适宜不容许反复中奖的场景)、SRANDMEMBER(随机获取汇合中的元素,适宜容许反复中奖的场景)。

Sorted Set(有序汇合)

介绍

Sorted Set 相似于 Set,但和 Set 相比,Sorted Set 减少了一个权重参数 score,使得汇合中的元素可能按 score 进行有序排列,还能够通过 score 的范畴来获取元素的列表。有点像是 Java 中 HashMapTreeSet 的结合体。

常用命令

命令介绍
ZADD key score1 member1 score2 member2 ...向指定有序汇合增加一个或多个元素
ZCARD KEY获取指定有序汇合的元素数量
ZSCORE key member获取指定有序汇合中指定元素的 score 值
ZINTERSTORE destination numkeys key1 key2 ...将给定所有有序汇合的交加存储在 destination 中,对雷同元素对应的 score 值进行 SUM 聚合操作,numkeys 为汇合数量
ZUNIONSTORE destination numkeys key1 key2 ...求并集,其它和 ZINTERSTORE 相似
ZDIFF destination numkeys key1 key2 ...求差集,其它和 ZINTERSTORE 相似
ZRANGE key start end获取指定有序汇合 start 和 end 之间的元素(score 从低到高)
ZREVRANGE key start end获取指定有序汇合 start 和 end 之间的元素(score 从高到底)
ZREVRANK key member获取指定有序汇合中指定元素的排名(score 从大到小排序)

更多 Redis Sorted Set 命令以及具体使用指南,请查看 Redis 官网对应的介绍:https://redis.io/commands/?gr... 。

基本操作

> ZADD myZset 2.0 value1 1.0 value2(integer) 2> ZCARD myZset2> ZSCORE myZset value12.0> ZRANGE myZset 0 11) "value2"2) "value1"> ZREVRANGE myZset 0 11) "value1"2) "value2"> ZADD myZset2 4.0 value2 3.0 value3(integer) 2
  • myZset : value1(2.0)、value2(1.0) 。
  • myZset2value2 (4.0)、value3(3.0) 。

获取指定元素的排名

> ZREVRANK myZset value10> ZREVRANK myZset value21

求交加

> ZINTERSTORE myZset3 2 myZset myZset21> ZRANGE myZset3 0 1 WITHSCORESvalue25

求并集

> ZUNIONSTORE myZset4 2 myZset myZset23> ZRANGE myZset4 0 2 WITHSCORESvalue12value33value25

求差集

> ZDIFF 2 myZset myZset2 WITHSCORESvalue12

利用场景

须要随机获取数据源中的元素依据某个权重进行排序的场景

  • 举例 :各种排行榜比方直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者光荣中的段位排行榜、话题热度排行榜等等。
  • 相干命令 :ZRANGE (从小到大排序) 、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。

《Java 面试指北》 的「技术面试题篇」就有一篇文章具体介绍如何应用 Sorted Set 来设计制作一个排行榜。

须要存储的数据有优先级或者重要水平的场景 比方优先级工作队列。

  • 举例 :优先级工作队列。
  • 相干命令 :ZRANGE (从小到大排序) 、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。

参考

  • Redis Data Structures :https://redis.com/redis-enter... 。
  • Redis Commands : https://redis.io/commands/ 。
  • Redis Data types tutorial:https://redis.io/docs/manual/... 。
  • Redis 存储对象信息是用 Hash 还是 String : https://segmentfault.com/a/11...

后记

专一 Java 原创干货分享,大三开源 JavaGuide (「Java学习+面试指南」一份涵盖大部分 Java 程序员所须要把握的外围常识。筹备 Java 面试,首选 JavaGuide!),目前曾经 120k+ Star。

原创不易,欢送点赞分享,欢送关注我在思否的账号,我会继续分享原创干货!加油,冲!

如果本文对你有帮忙的话,欢送点赞分享,这对我持续分享&创作优质文章十分重要。感激