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五种基本数据类型

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

上图中:设置一个键为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命令 同时设置/获取一个或者多个键值对,主要就是批量设置和获取键值对。


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

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

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


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


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


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


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


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


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


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

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


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


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

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

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


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

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

  • 统计多单位的数量

  • 粉丝数

  • 对象缓存存储

Hash散列表

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

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

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


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

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

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

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

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

  • 格式为:hmget key field1 … fieldN


  • (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

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

使用场景

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

List链表

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • 小结:

  • 实际上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 的集合是字符串的无序集合。

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

SortedSet( 有序集合) zset

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

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

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

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

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

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

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

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

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

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

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

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

面试题常问的数据类型

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合成一条指令来用的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/347641.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【驱动】TI AM437x(内核调试-07):devmem2直接读写内存、寄存器,devkmem读取内核变量

1、/dev/mem 和 /dev/kmem 1)/dev/mem: 物理内存的全镜像。可以用来访问物理内存 2)/dev/kmem: kernel看到的虚拟内存的全镜像。可以用来访问kernel的内容。kernel部分内存用户空间本不可访问。但是因为所有进程共享内核空间的页表。所以内核虚拟地址对应物理地址是确定的…

【码农新闻】 CSS 即将支持嵌套,SASS/LESS 等预处理器已无用武之地?常见的Web攻击手段,拿捏了!......

目录 【码农新闻】 CSS 即将支持嵌套,SASS/LESS 等预处理器已无用武之地?常见的Web攻击手段,拿捏了!...... 流行框架与库的源码分析与最简实现CSS 即将支持嵌套,SASS/LESS 等预处理器已无用武之地?常见的W…

低代码开发平台与可组合业务:实现高效应用的完美结合

如今,有很多产品已经走在了模块化的道路上,例如一款吸尘器,它可以经由不同配件组合来实现不同的功能,来满足消费者的需求。这种类似于“一站式”的产品解决方案,正在成为一种可见的趋势。 今年年初,Gartne…

函数递归知识点与经典例题

目录 递归的概念 (什么是递归) 递归举例 举例1:求n的阶乘 举例2:顺序打印一个整数的每一位 递归与迭代 举例3:求第n个斐波那契数 递归的概念 (什么是递归) 递归是学习C语言函数绕不开的⼀…

第13章_泛型(集合中使用泛型,比较器中使用泛型,自定义泛型结构,泛型在继承上的体现,通配符的使用)

文章目录 第13章_泛型(Generic)本章专题与脉络1. 泛型概述1.1 生活中的例子1.2 泛型的引入 2. 使用泛型举例2.1 集合中使用泛型2.1.1 举例2.1.2 练习 2.2 比较器中使用泛型2.2.1 举例2.2.2 练习 2.3 相关使用说明 3. 自定义泛型结构3.1 泛型的基础说明3.2 自定义泛型类或泛型接…

一文学习Thrift RPC

Thrift RPC引言 Thrift RPC的特点 Thrift 是一个RPC的框架,和Hessian RPC有什么区别,最重要的区别是Thrift可以做异构系统开发。 什么是异构系统,服务的提供者和服务的调用者是用不同语言开发的。 为什么会当前系统会有异构系统的调用&…

Flume介绍

一、介绍 Apache Flume 是一种分布式、可靠且可用的系统,用于有效地收集、汇总大量日志数据,并将其从多个不同来源转移到集中式数据存储区。 Apache Flume 的使用不仅限于日志数据聚合。由于数据源是可定制的,Flume 可用于传输大量事件数据&a…

C++学习| QT快速入门

QT简单入门 QT Creater创建QT项目选择项目类型——不同项目类型的区别输入项目名字和路径选择合适的构建系统——不同构建系统的却别选择合适的类——QT基本类之间的关系Translation File选择构建套件——MinGW和MSVC的区别 简单案例:加法器设计界面——构建加法器界…

红帽认证有啥用?初级红帽认证证书值得考吗?

大家好,这里是G-LAB IT实验室。 今天我们来了解一下Linux红帽认证。 红帽认证已成为企业和个人竞相追逐的热门资质。 红帽认证认可度究竟如何?红帽RHCSA认证含金量又有多高? 下面G-LAB将为你一一解答。 1 、红帽认证认可度怎么样? 事实上&#xff0…

git:git reset 和 git revert

在使用 git 进行项目开发的过程中,有时会出现错误提交的情况,这时就需要能够撤销错误的提交,将代码恢复到提交之前的样子。根据不同情况,可以使用 git reset 或 git revert 命令。 一. git reset git reset 的原理是修改 HEAD 的…

php怎么输入一个变量,http常用的两种请求方式getpost(ctf基础)

php是网页脚本语言,网页一般支持两种提交变量的方式,即get和post get方式传参 直接在网页URL的后面写上【?a1027】,如果有多个参数则用&符号连接, 如【?a10&b27】 post方式传参 需要借助插件,ctfer必备插…

羊奶与牛奶,谁更好?

羊奶与牛奶,谁更好? 羊奶和牛奶是我们日常饮食中常见的乳制品,但究竟哪种更好呢?今天就让小编羊大师带大家一起来探讨一下,看看羊奶和牛奶在各方面的优势和劣势,帮助你作出更明智的选择。 让我们从营养价…

仅使用 Python 创建的 Web 应用程序(前端版本)第07章_商品列表

在本章中,我们将实现一个产品列表页面。 完成后的图像如下 创建过程与User相同,流程如下。 No分类内容1Model创建继承BaseDataModel的数据类Item2MockDB创建产品表并生成/添加虚拟数据3Service创建一个 ItemAPIClient4Page定义PageId并创建继承自BasePage的页面类5Applicati…

常见算法思想:迭代法

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖&…

vue3 实现百分比进度条,文件上传进度条,包更新进度条

包更新&#xff0c; 文件上传&#xff0c;进度条 template 里面 <van-button click"changerun">{{ run?暂停:播放 }}</van-button>{{ percentage }}%<div class"line" :style"{height:2px, width:percentage%, backgroundColor:perc…

Linux中的LVM理论

Linux LVM&#xff1a;Logical Volume Manager逻辑卷管理 无需在停机的情况下&#xff0c;动态调整分区的大小 PV里面的存在很多小方块PE&#xff08;物理扩展&#xff09;&#xff0c;一个PV继承了pp的100G&#xff0c;只不过被分开分配了 划分小的PE再存放在VG里面&#…

两相步进电机驱动原理

两相步进电机驱动 前言什么是步进电机驱动器细分控制电机内部结构图片步进电机驱动原理&#xff08;重要&#xff09;步进电机参数&#xff11;、步距角&#xff1a;收到一个脉冲转动的角度&#xff12;、细分数 &#xff1a;&#xff11;&#xff0f;&#xff12;&#xff0c…

常见の算法

前言本文主要使用Java 什么&#xff0c;是快乐星球#&#xffe5;%……什么是算法&#xff1f; 算法是一组完成任务的指令。任何代码片段都可视为算法&#xff0c;但我们主要介绍常见算法 一、引入——二分查找 二分查找是一种算法&#xff0c;其输入是一个有序的元素列表。如…

JSON-handle工具安装及使用

目录 介绍下载安装简单操作 介绍 JSON-Handle 是一款非常好用的用于操作json的浏览器插件&#xff0c;对于开发人员和测试人员来说是一款很好用的工具&#xff0c;如果你还没有用过&#xff0c;请赶紧下载安装吧&#xff0c;下面是安装过程和具体使用。 下载安装 点击下载JSON…

springboot项目快速引入knife4j

引入依赖 <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version> </dependency>knife4j配置文件 basePackage改为自己存放接口的包名 /*** Kn…