Redis的五种常用数据类型详解及相关面试问题

目录

Redis的五种常用数据类型详解

简述

Redis五种基本数据类型

String字符串

常用命令

应用场景

Hash散列表

常用命令

使用场景

List链表

常用命令

应用场景

Set( 集合)

常用命令

应用场景

SortedSet( 有序集合) zset

常用命令介绍

应用场景

面试题常问的数据类型

简述

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings),散列(hashes), 列表(lists),集合(sets),有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询 。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

Redis的英文官网

Redis的中文官网

Redis的中文命令手册

本文主要介绍Redis五种常用的数据类型、三种特殊的数据类型的使用、应用场景。

Redis五种基本数据类型

Redis的五种常用数据类型详解及相关面试问题_第1张图片

String字符串

Redis 字符串是字节序列。Redis 字符串是二进制安全的,这意味着他们有一个已知的长度没有任何特殊字符终止,所以你可以存储任何东西,512 M为上限,主要的还是操作键值对。 String的数据结构是简单的Key-Value模型,Value可以是字符串,也可以是数字。

常用命令
  • 添加元素(SET命令)

格式:

set key value [expiration EX seconds|PX milliseconds] [NX|XX]

ex:秒级过期时间,nx:键不存在时才能设置成功,xx键存在时才能设置成功

(1)普通添加: set key value

(2)设置过期时间 setex: setex key seconds value

Redis的五种常用数据类型详解及相关面试问题_第2张图片

上图中:设置一个键为key1,值为hello,并且30秒后过期。 使用 ttl命令 可以查看该键还有多少时间过期。

(3)不存在设置 setnx(set if not exist) setnx key value 如果key不存在,则创建一个key,如果key存在,则创建失败并返回0。

上图中,执行第一条命令时,由于key2不存在,所以就创建一个key2,执行第二句命令时,由于key2前面已经创建了,已经存在了,所以就创建失败,并且返回0。

setnx在分布式锁中经常使用到


  • 获取值 (GET命令)

127.0.0.1:6379> set name oldou

OK

127.0.0.1:6379> get name   #获取name中的值

"oldou"


  • mset/mget命令 同时设置/获取一个或者多个键值对,主要就是批量设置和获取键值对。

Redis的五种常用数据类型详解及相关面试问题_第3张图片


  • msetnx key1 value1 key2 value2… 同时设置多个值,如果其中有一个存在,那么就都创建失败。 要么一起成功,要么一起失败,这是一个 原子性操作

  • incr命令 让当前键值以 1 的数量递增,并返回递增后的值。相当于Java中的自增,每次使用改命令都能让变量自增1。

Redis的五种常用数据类型详解及相关面试问题_第4张图片

  • 应用场景:(一般可用于设置浏览量、阅读量)


  • incrby命令 可以指定参数一次增加的数值,并返回递增后的值,(原来的num是2,加10之后变为12)


  • decr命令 可以指定参数一次递减的数值,并返回递减后的值,每次使用该命令都自减1,相当于Java中的自减。

Redis的五种常用数据类型详解及相关面试问题_第5张图片


  • decrby 可以指定参数一次递减的数值,并返回递减后的值

Redis的五种常用数据类型详解及相关面试问题_第6张图片


  • append命令 向键值的末尾追加 value。如果键不存在则将该键的值设置为 value。 返回值是追加后字符串的总长度。

Redis的五种常用数据类型详解及相关面试问题_第7张图片


  • strlen命令 :获取字符串长度

Redis的五种常用数据类型详解及相关面试问题_第8张图片


  • **getrange命令:**截去指定索引的字符串

Redis的五种常用数据类型详解及相关面试问题_第9张图片


  • setrange命令 :从指定索引开始替换字符串

Redis的五种常用数据类型详解及相关面试问题_第10张图片

  • 以上表示从索引为0开始的元素替换为QQQQQ


  • del命令 : 根据key删除一个或者多个元素

Redis的五种常用数据类型详解及相关面试问题_第11张图片


  • 设置对象 set user:1 {name:zhangsan,age:3}

  • 设置一个user:1对象,值为json字符串来保存一个对象。

  • 这是一个巧妙的设计: user:{id}:{field} 如此设置在Redis中是完全OK的。

Redis的五种常用数据类型详解及相关面试问题_第12张图片


  • getset命令 :先get然后再set 如果设置的键不存在值,则设置值,并且返回nil 如果设置的键存在值,则返回该值,并设置新的值

Redis的五种常用数据类型详解及相关面试问题_第13张图片

应用场景
  • 计数器—点赞,视频播放量,每播放一次就+1

  • 统计多单位的数量

  • 粉丝数

  • 对象缓存存储

Hash散列表

Redis的五种常用数据类型详解及相关面试问题_第14张图片

Redis 的哈希是键值对的集合。

Redis 的哈希值是字符串字段和字符串值之间的映射,因此它们被用来表示对象,还有用户信息之类的,经常变动的信息。

Hash更适合用于对象的存储,String更适合字符串存储。


常用命令
  • (1) hset命令 :存储一个哈希键值对的集合 格式为:hset key field value -----表示的是在key的field下设置一个为“value”的值。

  • (2) hget命令 :获取一个哈希键的值    格式为:hget key field

Redis的五种常用数据类型详解及相关面试问题_第15张图片

  • (3) hmset : 存储一个或多个哈希是键值对的集合

  • 格式为:hmset key field1 value1 …fieldN keyN

  • (4) hmget : 获取多个指定的键的值       

  • 格式为:hmget key field1 … fieldN

Redis的五种常用数据类型详解及相关面试问题_第16张图片


  • (5) hexists : 判断哈希表中的字段名是否存在 如果存在返回 1 否则返回 0

  • 格式为:hexists key field

  • (6) hdel : 删除一个或多个字段

  • 格式为:hdel key field

  • (7) hgetall : 获取一个哈希是键值对的集合

  • 格式为:hgetall key

  • (8) hvals : 只返回字段值

  • 格式为:hvals key

  • (9) hkeys : 只返回字段名

  • 格式为:hkeys key

  • (10) hlen : 返回 key 的 hash 的元素个数

  • 格式为:hlen key

  • 这里是因为user下有两个属性 username和userage


  • (11) hincrby key field value : 指定增量value

Redis的五种常用数据类型详解及相关面试问题_第17张图片

  • (12) hsetnx key field value : 如果该键不存在就创建,如果该键存在就创建失败。

使用场景

主要用于存储部分变更数据,比如存储用户信息等等

List链表

Redis的五种常用数据类型详解及相关面试问题_第18张图片

Redis 的链表是简单的字符串列表,排序插入顺序。您可以添加元素到 Redis 的列表的头部或尾部 Lpush:表示的是向链表的左添加,也就是向链表的头添加; Rpush:表示的是向链表的右添加,也就是向链表的尾添加;

常用命令
  • (1) lpush key value : 向链表左侧添加—头插法

Redis的五种常用数据类型详解及相关面试问题_第19张图片

  • (2) rpush key value : 向链表右侧添加–尾插法

Redis的五种常用数据类型详解及相关面试问题_第20张图片

  • (3) lpop key : 从左边移出一个元素,就是从最左边的那个节点剔除掉。

Redis的五种常用数据类型详解及相关面试问题_第21张图片

  • (4) rpop key : 从右边移出一个元素,就是从最右边的那个节点剔除掉。

Redis的五种常用数据类型详解及相关面试问题_第22张图片

  • (5) lrange key start end lrange : 命令将返回索引从 start 到 stop 之间的所有元素。Redis 的列表起始索引为 0。

  • 如果是要获取全部的元素: lrange key 0 -1

  • (6) llen key : 返回链表中元素的个数 相当于关系型数据库中 select count(*)

Redis的五种常用数据类型详解及相关面试问题_第23张图片

  • (7) lindex key indexnumber :lindex 命令用来返回指定索引的元素,索引从 0 开始,如果是负数表示从右边开始计算的索引,最右边元素的索引是-1。如果要将列表类型当做数组来用,lindex 命令是必不可少的。

Redis的五种常用数据类型详解及相关面试问题_第24张图片

  • (8) lset key indexnumber value : 是另一个通过索引操作列表的命令,它会将索引为 index的元素赋值为 value,原来的值会被覆盖。如果该列表不存在就会报错。所以使用这个命令之前先使用exists判断一下。

Redis的五种常用数据类型详解及相关面试问题_第25张图片

  • (9) lrem key count value : 移除key链表中count个元素的value值,精确匹配,如果链表中可以有多个重复的值,这里的count指的是可以删除多个相同key的值。

Redis的五种常用数据类型详解及相关面试问题_第26张图片

  • (10) ltrim list startIndex endIndex :通过下标截取指定的长度,这个时候list已经改变了,只剩下截断的元素。

Redis的五种常用数据类型详解及相关面试问题_第27张图片

  • (11) rpoplpush source destination :移除当前的source链表中的最后一个元素,并且将该元素移动到destination链表当中。

Redis的五种常用数据类型详解及相关面试问题_第28张图片

  • (12) linsert key BEFORE|AFTER pivot value :在key列表的pivot元素的前/后面插入元素value。

Redis的五种常用数据类型详解及相关面试问题_第29张图片

  • 小结:

  • 实际上list是一个链表,before node after,left ,right都可以插入值;

  • 如果key不存在,就创建新的链表;

  • 如果key存在就创建新的值;

  • 如果移除了所有的值,空链表,也就代表不存在;

  • 在两边插入或者改动值,效率最高,中间元素相对来说效率会低一点。

应用场景
  • 消息队列:利用List的PUSH操作,将任务存在List中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作List中某一段的api,你可以直接查询,删除List中某一段的元素。

  • 消息排队,消息队列(Lpush、Rpop)、栈(Lpush、Lpop)

  • 使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。

Set( 集合)

Redis的五种常用数据类型详解及相关面试问题_第30张图片

Redis 的集合是字符串的无序集合。

在Set集合当中,是不允许有重复的。

set是通过hash table实现的,可以进行添加、删除和查找。对集合我们可以取并集,交集,差集.

常用命令
  • (1) sadd key value :添加一个 string 元素到,key 对应的 set 集合中, 成功返回 1,如果元素已经在集合中返回 0

Redis的五种常用数据类型详解及相关面试问题_第31张图片

  • (2) scard key : 返回 set 的元素个数,如果 set 是空或者 key 不存在返回 0

Redis的五种常用数据类型详解及相关面试问题_第32张图片

  • (3) smembers key : 返回 key 对应 set 的所有元素,结果是无序的

Redis的五种常用数据类型详解及相关面试问题_第33张图片

  • (4) sismember key value : 判断 value 是否在 set 中,存在返回 1,0 表示不存在或者 key 不存在

Redis的五种常用数据类型详解及相关面试问题_第34张图片

  • (5) srem key value : 从 key 对应 set 中移除给定元素,成功返回 1,如果 value 在集合中不存在或者 key 不存在返回 0

Redis的五种常用数据类型详解及相关面试问题_第35张图片

  • (6) srandmember key nums : 从key集合中随机抽取nums个元素。

Redis的五种常用数据类型详解及相关面试问题_第36张图片

  • (7) spop key :随机删除一些key集合中的元素。

Redis的五种常用数据类型详解及相关面试问题_第37张图片

  • (8) smove source destination member :将原集合source中的member元素移动到destination集合中。

Redis的五种常用数据类型详解及相关面试问题_第38张图片


  • (9) sdiff key1 key2 :取出key1中与key2集合的不同元素,差集

Redis的五种常用数据类型详解及相关面试问题_第39张图片

  • (10) sinter key1 key2 :取key1与key2两个集合中相同的元素,交集

Redis的五种常用数据类型详解及相关面试问题_第40张图片

  • (11) sunion key1 key2 :将key1与key2两个集合中的元素合在一起,并集

Redis的五种常用数据类型详解及相关面试问题_第41张图片

应用场景
  • 微博、用户将所有关注的人都放入到一个set集合当中,将它的粉丝也放在一个集合中。

  • 共同关注、共同爱好、二度好友、QQ的好友推荐(六度分割理论)

SortedSet( 有序集合) zset

Redis 的有序集合类似于 Redis 的集合,字符串不重复的集合。

常用命令介绍
  • (1) zadd key score value : 将一个或多个 value 及其 socre 加入到 set 中

Redis的五种常用数据类型详解及相关面试问题_第42张图片

  • (2) zrange key start end :0 和-1 表示从索引为 0 的元素到最后一个元素(同 LRANGE 命令相似)

  • (3) zrange key 0 -1 withscores 也可以连同 score 一块输出,使用 WITHSCORES 参数

Redis的五种常用数据类型详解及相关面试问题_第43张图片

  • (4) zremrangebyscore key start end :可用于范围删除操作

Redis的五种常用数据类型详解及相关面试问题_第44张图片

  • (5) zrangebyscore key min max : 升序排序操作,将key按最小值到最大值进行输出。 zrevrange salary 0 -1 :这个是倒序全部输出

Redis的五种常用数据类型详解及相关面试问题_第45张图片

  • 以上是从小到大排序,也就是升序排序。

  • (6) zrevrangebyscore key max min :倒序排序操作,将key按照从大到小排序输出

Redis的五种常用数据类型详解及相关面试问题_第46张图片

  • (6) zrem key value : 删除指定的元素

Redis的五种常用数据类型详解及相关面试问题_第47张图片

  • (7) zcard key :获取有序集合中的个数

Redis的五种常用数据类型详解及相关面试问题_第48张图片

  • (8) zcount key min max : 获取指定区间的成员数量

Redis的五种常用数据类型详解及相关面试问题_第49张图片

应用场景
  • 存储班级成绩表、工资表排序

面试题常问的数据类型

1、Redis 的数据类型有哪些?
  • Redis支持五种数据类型:String(字符串)、hash(哈希)、list(列表)、set(集合)以及zsetsorted set(有序集合)。

  • 我们实际项目中比较常用的是String和hash,如果你是Redis的中高级用户,还需要加上以下几种数据类型,分别是:HyperLogLog、Geo、Pub/Sub。

  • 如果你玩过Redis Module,像BloomFilter、RedisSearch、Redis-ML,,等等,是加分项。

2、一个字符串类型的值能存储最大容量是多少?

一个字符串类型的值能存储的最大容量为512M。

3、Redis key 的过期时间和永久有效分别怎么设置?
  • 使用expire命令对key的过期时间进行设置;

  • 使用persist命令对key永久有效进行设置;

4、一个 Redis 实例最多能存放多少的 keys?List、Set、Sorted Set他们最多能存放多少元素?

理论上Redis可以处理多达232个keys,并且在实际中进行了测试,每个实例至少存放了2亿5千万的keys。

任何list、set和sorted set都可以放232个元素,换句话说,Redis的存储极限是系统中的可用内存值。

5、Redis 最适合的场景?
  • (1)会话缓存(最常用的一种使用 Redis 的情景是会话缓存(session cache)。用 Redis 缓存会话比其他存储(如 Memcached)的优势在于:Redis 提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗? 幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用 Redis 来缓存会话的文档。甚至广为人知的商业平台Magento 也提供 Redis 的插件。

  • (2)全页缓存(FPC) 除基本的会话 token 之外,Redis 还提供很简便的 FPC 平台。回到一致性问题,即使重启了 Redis 实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似 PHP 本地 FPC。 再次以 Magento 为例,Magento提供一个插件来使用 Redis 作为全页缓存后端。 此外,对 WordPress 的用户来说,Pantheon 有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

  • (3)队列 Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得 Redis能作为一个很好的消息队列平台来使用。Redis 作为队列使用的操作,就类似于本地程序语言(如 Python)对 list 的 push/pop 操作。 如果你快速的在 Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用 Redis 创建非常好的后端工具,以满足各种队列需求。例如,Celery 有一个后台就是使用 Redis 作为 broker,你可以从这里去查看。

  • (4)排行榜/计数器 Redis 在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的 10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: ZRANGE user_scores 0 10 WITHSCORES Agora Games 就是一个很好的例子,用 Ruby 实现的,它的排行榜就是使用 Redis 来存储数据的,你可以在这里看到。

  • (5)发布/订阅 最后(但肯定不是最不重要的)是 Redis 的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用 Redis 的发布/订阅功能来建立聊天系统!)

6、假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?

使用keys指令可以扫出指定模式的key列表。

7、如果这个Redis正在给线上的业务提供服务,那使用keys指令会有什么问题? 这个时候就要回答:Redis是单线程的,keys指令会导致线程阻塞一段时间,线上服务会停顿,知道指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取指令模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
8、如果有大量的 key 需要设置同一时间过期,一般需要注意什么?

如果大量的key过期时间设置过于集中,那么到过期的那个时间点,Redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一点。

9、使用过 Redis 做异步队列么,你是怎么用的?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。 当lpop没有消息的时候,要适当sleep一会儿再重试。

追问:可不可以不使用sleep呢?

list还有个指令叫blpop,在没有消息的时候,它会阻塞住,直到消息到来。

再追问:能不能生产一次,消费多次呢?

使用pub/sub主题订阅者模式,可以使用1:N的消息队列。

再问:pub/sub有什么缺点?

在消费者下线的情况下,生产的消息会丢失,解决这样的问题得使用专业的消息队列,如RabbitMQ等。

Redis如何实现延时队列呢?

使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangbyscore指令获取N秒之前的数据轮询进行处理。

10、使用过 Redis 分布式锁么,它是什么回事?

先拿setnx来争抢锁,抢到之后再用expire给锁加一个过期时间防止锁忘记了释放。

问:如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?

这个时候确实锁会永远得不到释放了,但是set指令有个非常复杂的参数是可以同时把setnx和expire合成一条指令来用的。

你可能感兴趣的:(JAVA全栈学习路线,#,JavaEE(SSM),java,后端,redis,缓存,面试)