首发于: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 存储更节俭内存)。
- 相干命令 :
SET
、GET
。
须要计数的场景
- 举例 :用户单位工夫的申请数(简略限流能够用到)、页面单位工夫的拜访数。
- 相干命令 :
SET
、GET
、INCR
、DECR
。
分布式锁
利用 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
利用场景
信息流展现
- 举例 :最新文章、最新动静。
- 相干命令 :
LPUSH
、LRANGE
。
音讯队列
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
:value1
、value2
。mySet2
:value2
、value3
。
求交加 :
> 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 中 HashMap
和 TreeSet
的结合体。
常用命令
命令 | 介绍 |
---|---|
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) 。myZset2
:value2
(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。
原创不易,欢送点赞分享,欢送关注我在思否的账号,我会继续分享原创干货!加油,冲!
如果本文对你有帮忙的话,欢送点赞分享,这对我持续分享&创作优质文章十分重要。感激