写点什么

Redis 高频面试题之缓存穿透、缓存击穿和缓存雪崩

用户头像
Java架构师
关注
发布于: 1 小时前

一、概述

  • Redis 是什么?what?


Redis(Remote Dictionary Server ),即远程字典服务 ! 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。



redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了 master-slave(主从)同步。 免费和开源!是当下最热门的 NoSQL 技术之一!也被人们称之为结构化数据库!


  • Redis 能干嘛?


1、内存存储、持久化,内存中是断电即失、所以说持久化很重要(rdb、aof) 2、效率高,可以用于高速缓存 3、发布订阅系统 4、地图信息分析 5、计时器、计数器(浏览量!) 6、........

二、Redis 的基本了解

  1. 首先我们可以看下官方文档是如何介绍 Redis 的:


①、英文文档 点击跳转.



②、中文文档 点击跳转.



2. Redis-Key 简单介绍一下 Redis 中队 Key 的操作命令。希望大家可以跟着注释敲一遍,简单记一下,都是最常用的命令!


127.0.0.1:6379> ping  #查看当前连接是否正常,正常返回PONGPONG127.0.0.1:6379> clear  #清楚当前控制台(为了更好的看到下面输入的命令)127.0.0.1:6379> keys *  #查看当前库里所有的key1) "db"127.0.0.1:6379> FLUSHALL  #清空所有库的内容OK127.0.0.1:6379> keys * (empty array)127.0.0.1:6379> set name dingdada  #添加一个key为‘name’ value为‘dingdada’的数据OK127.0.0.1:6379> get name  #查询key为‘name’的value值"dingdada"127.0.0.1:6379> keys *1) "name"127.0.0.1:6379> set name1 dingdada2OK127.0.0.1:6379> get name1"dingdada2"127.0.0.1:6379> keys *  #查看当前库里所有的key1) "name1"2) "name"127.0.0.1:6379> EXISTS name  #判断当前key是否存在(integer) 1127.0.0.1:6379> move name 1  #移除当前库1的key为‘name‘的数据(integer) 1127.0.0.1:6379> keys *1) "name1"127.0.0.1:6379> FLUSHALL  #再次清空所有库的内容OK
## 多加几条数据 下面测试设置key的过期时间127.0.0.1:6379> set name dingdadaOK127.0.0.1:6379> set name1 dingdada1OK127.0.0.1:6379> set name2 dingdada2OK127.0.0.1:6379> EXPIRE name 15 #设置key为’name‘的数据过期时间为15秒 单位seconds(integer) 1127.0.0.1:6379> ttl name #查看当前key为’name‘的剩余生命周期时间(integer) 13127.0.0.1:6379> ttl name(integer) 12127.0.0.1:6379> ttl name(integer) 11127.0.0.1:6379> ttl name(integer) 8127.0.0.1:6379> ttl name(integer) 6127.0.0.1:6379> ttl name(integer) 3127.0.0.1:6379> ttl name(integer) 2127.0.0.1:6379> ttl name(integer) 1127.0.0.1:6379> ttl name(integer) 0127.0.0.1:6379> ttl name #如若返回-2,证明key已过期(integer) -2127.0.0.1:6379> get name #再次查询即为空(nil)127.0.0.1:6379> type name1string127.0.0.1:6379>
复制代码


如若遇到不会的命令!记得查看 Redis 中文官网,上面有官方文档!链接上面有,可以点击跳转~

二、Redis 的五大数据类型

  1. String(字符串)


添加查询追加获取长度判断是否存在的操作


127.0.0.1:6379> set name dingdada  #插入一个key为‘name’值为‘dingdada’的数据OK127.0.0.1:6379> get name  #获取key为‘name’的数据"dingdada"127.0.0.1:6379> get key1"hello world!"127.0.0.1:6379> keys *  #查看当前库的所有数据1) "name"127.0.0.1:6379> EXISTS name  #判断key为‘name’的数据存在不存在,存在返回1(integer) 1127.0.0.1:6379> EXISTS name1  #不存在返回0(integer) 0127.0.0.1:6379> APPEND name1 dingdada1  #追加到key为‘name’的数据后拼接值为‘dingdada1’,如果key存在类似于java中字符串‘+’,不存在则新增一个,类似于Redis中的set name1 dingdada1 ,并且返回该数据的总长度(integer) 9127.0.0.1:6379> get name1"dingdada1"127.0.0.1:6379> STRLEN name1  #查看key为‘name1’的字符串长度(integer) 9127.0.0.1:6379> APPEND name1 ,dingdada2  #追加,key存在的话,拼接‘+’,返回总长度(integer) 19127.0.0.1:6379> STRLEN name1(integer) 19127.0.0.1:6379> get name1"dingdada1,dingdada2"127.0.0.1:6379> set key1 "hello world!"  #注意点:插入的数据中如果有空格的数据,请用“”双引号,否则会报错!OK127.0.0.1:6379> set key1 hello world!  #报错,因为在Redis中空格就是分隔符,相当于该参数已结束(error) ERR syntax error127.0.0.1:6379> set key1 hello,world!  #逗号是可以的OK
复制代码


自增自减操作


127.0.0.1:6379> set num 0  #插入一个初始值为0的数据OK127.0.0.1:6379> get num"0"127.0.0.1:6379> incr num  #指定key为‘num’的数据自增1,返回结果  相当于java中 i++(integer) 1127.0.0.1:6379> get num  #一般用来做文章浏览量、点赞数、收藏数等功能"1"127.0.0.1:6379> incr num(integer) 2127.0.0.1:6379> incr num(integer) 3127.0.0.1:6379> get num"3"127.0.0.1:6379> decr num  #指定key为‘num’的数据自减1,返回结果  相当于java中 i--(integer) 2127.0.0.1:6379> decr num(integer) 1127.0.0.1:6379> decr num(integer) 0127.0.0.1:6379> decr num  #可以一直减为负数~(integer) -1127.0.0.1:6379> decr num  #一般用来做文章取消点赞、取消收藏等功能(integer) -2127.0.0.1:6379> decr num(integer) -3127.0.0.1:6379> INCRBY num 10  #后面跟上by  指定key为‘num’的数据自增‘参数(10)’,返回结果(integer) 7127.0.0.1:6379> INCRBY num 10(integer) 17127.0.0.1:6379> DECRBY num 3  #后面跟上by  指定key为‘num’的数据自减‘参数(3)’,返回结果(integer) 14127.0.0.1:6379> DECRBY num 3(integer) 11
复制代码


截取替换字符串操作


#截取127.0.0.1:6379> set key1 "hello world!"OK127.0.0.1:6379> get key1"hello world!"127.0.0.1:6379> GETRANGE key1 0 4  #截取字符串,相当于java中的subString,下标从0开始,不会改变原有数据"hello"127.0.0.1:6379> get key1"hello world!"127.0.0.1:6379> GETRANGE key1 0 -1  #0至-1相当于 get key1,效果一致,获取整条数据"hello world!"#替换127.0.0.1:6379> set key2 "hello,,,world!"OK127.0.0.1:6379> get key2"hello,,,world!"127.0.0.1:6379> SETRANGE key2 5 888  #此语句跟java中replace有点类似,下标也是从0开始,但是有区别:java中是指定替换字符,Redis中是从指定位置开始替换,替换的数据根据你所需替换的长度一致,返回值是替换后的长度(integer) 14127.0.0.1:6379> get key2"hello888world!"127.0.0.1:6379> SETRANGE key2 5 67  #该处只替换了两位(integer) 14127.0.0.1:6379> get key2"hello678world!"
复制代码


设置过期时间不存在设置操作


#设置过期时间,跟Expire的区别是前者设置已存在的key的过期时间,而setex是在创建的时候设置过期时间127.0.0.1:6379> setex name1 15  dingdada  #新建一个key为‘name1’,值为‘dingdada’,过期时间为15秒的字符串数据OK127.0.0.1:6379> ttl name1  #查看key为‘name1’的key的过期时间(integer) 6127.0.0.1:6379> ttl name1(integer) 5127.0.0.1:6379> ttl name1(integer) 3127.0.0.1:6379> ttl name1(integer) 1127.0.0.1:6379> ttl name1(integer) 0127.0.0.1:6379> ttl name1  #返回为-2时证明该key已过期,即不存在(integer) -2#不存在设置127.0.0.1:6379> setnx name2 dingdada2  #如果key为‘name2’不存在,新增数据,返回值1证明成功(integer) 1127.0.0.1:6379> get name2"dingdada2"127.0.0.1:6379> keys *1) "name2"127.0.0.1:6379> setnx name2 "dingdada3"  #如果key为‘name2’的已存在,设置失败,返回值0,也就是说这个跟set的区别是:set会替换原有的值,而setnx不会,存在即不设置,确保了数据误操作~(integer) 0127.0.0.1:6379> get name2"dingdada2"
复制代码


msetmget 操作


127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3  #插入多条数据OK127.0.0.1:6379> keys *  #查询所有数据1) "k2"2) "k3"3) "k1"127.0.0.1:6379> mget k1 k2 k3  #查询key为‘k1’,‘k2’,‘k3’的数据1) "v1"2) "v2"3) "v3"127.0.0.1:6379> MSETNX k1 v1 k4 v4  #msetnx是一个原子性的操作,在一定程度上保证了事务!要么都成功,要么都失败!相当于if中的条件&&(与)(integer) 0127.0.0.1:6379> keys *1) "k2"2) "k3"3) "k1"127.0.0.1:6379> MSETNX k5 v5 k4 v4  #全部成功(integer) 1127.0.0.1:6379> keys *1) "k2"2) "k4"3) "k3"4) "k5"5) "k1"
复制代码


添加获取对象getset 操作


#这里其实本质上还是字符串,但是我们讲其key巧妙的设计了一下。##mset student:1:name  student 相当于类名,1 相当于id,name 相当于属性#如果所需数据全部这样设计,那么我们在java的业务代码中,就不需要关注太多的key#只需要找到student类,下面哪个id,需要哪个属性即可,减少了代码的繁琐,在一定程度上可以理解为这个一个类的对象!127.0.0.1:6379> mset student:1:name dingdada student:1:age 22  #新增一个key为‘student:1:name’,value为‘dingdada ’。。等数据OK127.0.0.1:6379> keys *  #查看所有的key1) "student:1:age"2) "student:1:name"127.0.0.1:6379> mget student:1:age student:1:name  #获取数据1) "22"2) "dingdada"
##getset操作127.0.0.1:6379> getset name1 dingdada1 #先get再set,先获取key,如果没有,set值进去,返回的是get的值(nil)127.0.0.1:6379> get name1"dingdada1"127.0.0.1:6379> getset name1 dingdada2 ##先获取key,如果有,set(替换)最新的值进去,返回的是get的值"dingdada1"127.0.0.1:6379> get name1 #替换成功"dingdada2"
复制代码


总结 String 是 Redis 中最常用的一种数据类型,也是 Redis 中最简单的一种数据类型。首先,表面上它是字符串,但其实他可以灵活的表示字符串、整数、浮点数 3 种值。Redis 会自动的识别这 3 种值。




路漫漫其修远兮,吾必将上下求索~ 因为篇幅所限,另开一篇文章写剩下的内容哦!如果你认为博主写的不错!写作不易,请点赞、关注、评论给博主一个鼓励吧~


作为阅读福利,我也整理了 Redis 相关的学习笔记(包含脑图、面试真题、手写 pdf 等)现在免费分享给阅读到本篇文章的 Java 程序员朋友们,需要的可【点击下方链接】即可获取!!!


最全学习笔记大厂真题+微服务+MySQL+分布式+SSM框架+Java+Redis+数据结构与算法+网络+Linux+Spring全家桶+JVM+高并发+各大学习思维脑图+面试集合



用户头像

Java架构师

关注

还未添加个人签名 2021.05.28 加入

还未添加个人简介

评论

发布
暂无评论
Redis高频面试题之缓存穿透、缓存击穿和缓存雪崩