面试知识总结

本文深入探讨了Spring Boot自动配置原理、单例模式设计、Spring Bean生命周期、MySQL执行计划、RPC接口幂等性、跨域问题解决方案、Redis与MySQL同步策略、缓存问题、分布式锁、消息队列应用及分布式事务解决方案等关键主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、springboot的自动配置原理
在这里插入图片描述2、ArrayList

fail-save读取的还是遍历之前的老数据,在遍历过程中添加进去的是在另一个数组里面,读写分离,
新添加进去的数据,会在下次遍历的时候才能遍历的到

在这里插入图片描述
3、LinKedList
在这里插入图片描述
4、HashMap
在这里插入图片描述在这里插入图片描述在这里插入图片描述
5、单例模式(控制一个类只有一个实例)

设计单例模式总体思路:
1、构造私有
2、提供一个私有的静态成员变量,类型就是本类类型,值就是本类对象
3、提够一个公共的静态方法,返回本类对象,供外部访问

在这里插入图片描述
1、饿汉式
在这里插入图片描述
2、枚举方式(饿汉式)

在这里插入图片描述3、懒汉式

只能运行在单线程情况下
在这里插入图片描述

加上synchronized能解决线程安全问题,但是性能受到很大影响。我们希望的是只在首次创建对象的时候,后面线程被等待,但是这里只要有线程进入方法的时候,后面线程都会等待
在这里插入图片描述

使用双重校验锁,对性能进行优化
在这里插入图片描述

懒汉式使用静态内部类来实现(推荐)
在这里插入图片描述

4、ApplicationContext refresh 流程

spring核心容器的初始化都会调用refresh方法,初始化之后才能正常工作

在这里插入图片描述

5、Spring bean 的生命周期

注意:@postConstruct 注解的方法init(),会在代理bean对象创建的时候执行,类似于创建对象是调用构造方法

在这里插入图片描述

6、Mysql执行计划分析

我们根据下图可以看出 ken_len 是 10 代表有2个字段选择了索引,type=range属于范围查询;

在这里插入图片描述结果分析
在这里插入图片描述
type=all 和 index 都属于 索引失效
在这里插入图片描述

7、mysql的组合索引

组合索引 ABC 的最左匹配原则 :
A、AB、AC、ABC都能匹配到,同时还具有阻断功能,例如
EXPLAIN SELECT * FROM test WHERE a_test=1 AND b_test>2 AND c_test=3
通过key_len 分析得出只有A、B走了索引,后面的C被范围查询阻断没有走索引
注意:尽量把范围查询放在最后面,放在最前面性能会很差

知识补充:key_len
在这里插入图片描述
知识补充:
mysql 中 int 类型和 string 类型 在被当做查询条件时该不该加单引号?

string类型和日期类型必须要加单引号,不然会严重影响性能,int类型不加,就算加了mysql执行的时候也会自动解析掉单引号,一个点就是根据数据在数据库的类型来

引申:一个表有2个索引分别是(A) 和 (A,B,C) 索引,那么执行WHERE A=1 AND B>2 AND C=3,会执行那个索引 ?
:测试得出会走ABC索引,因为两个索引所覆盖的列重叠 ,会判定为冗余索引,就会使用到ABC索引,同时SQL要走A、B 2个索引,所以A不满足

8、如何保证RPC接口幂等性问题

产生背景:在谈RPC幂等性问题 首先我们要知道客户端发送请求,业务代码执行时间>超时时间,服务端不能及时响应,这是属于幂等超时,解决方案可以延长请求的超时时间,推荐使用MQ进行异步操作;另外一种情况是属于 客户端发送请求,可能由于网络抖动、服务器不在、正在重启,导致这次请求失败,但是可能下一次请求就可能成功,那么这个时候我们可能就要执行重试策略,需要多次调用接口,在多次调用接口的情况下,就可能衍生一系列问题

什么是幂等?

概念:重复请求结果最终只算一次,保证结果的唯一性
引申:在MQ中,消费者如何避免重复消费的问题,在web中,如何防止用户重复提交表单,RPC接口如何保证幂等性问题,都属于幂等性问题

什么是幂等超时?(客户端不能及时响应)

幂等超时:客户端进行RPC远程调用的时候设置请求超时时间为5s,而我的业务代码需要执行7S,这个时候,业务逻辑时间 > 请求超时时间,就是抛出 Read timed out 异常,响应超时;这是很多RPC 框架的共性;
解决方案:我们可以把请求的超时时间延长,不推荐,这是治标不治本;一般可以使用MQ进行异步操作
引申:这种情况无论怎么重试(补偿),都是没有效果,拿不到响应结果。

为什么要使用RPC重试机制?(网络抖动、服务不在,正在重启)

RPC重试机制(补偿): 远程通信的时候,在一定的业务场景可能会设置请求的次数,因为可能存在网络抖动、服务不在的原因抛出 Connection refused:connect 异常导致请求失败,这时候就可以进行补偿,多次调用接口。
RPC概念:叫做远程调用接口,包括dubbo、feign、httpclient 等 内部都是通过 手写rpc框架来实现,原理:动态代理技术
解决方案:重试策略,间隔性的重复调用接口

使用RPC重试机制如何保证接口的幂等性?

在使用重试机制的时候可能会出现数据的重复插入、数据的重复修改问题

整体解决方案:
insert接口:全局id+主键索引

在这里插入图片描述在这里插入图片描述

update接口:使用version版本号实现乐观锁
在这里插入图片描述
2、修改相关信息(传入查询到的商品version版本号等相关商品信息)
在这里插入图片描述

9、跨域问题解决方案

背景:跨域问题一般发生在前后端分离的项目架构中,没有遵循同源策略(浏览器的自我保护机制),因为只要协议(http,https) + IP + 端口,其中任意一个对应不上都会发生跨域问题

解决整体思路:在接口的响应头中添加 access-control-allow-origin:* 参数 ,这样浏览器就能识别,放行该接口返回的数据

在接口或者方法上添加@CrossOrigin注解

这是spring提供的注解,原理是使用aop+反射技术,在响应头中添加 access-control-allow-origin:* 参数
但是这种情况解决在有很多接口,很多累的情况下显得比较冗余

使用CorsFIlter过滤器

拦截所用响应给前端的请求,添加access-control-allow-origin,如果是在微服务中,这把这个统一配置放在网关中

       @Configuration
    public class GulimallCorsConfiguration {
        /**
         * 功能描述:网关统一配置允许跨域
         *
         * @author cakin
         * @date 2020/10/25
         * @return CorsWebFilter 跨域配置过滤器
         */
        @Bean
        public CorsWebFilter corsWebFilter(){
            // 跨域配置源
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            // 跨域配置
            CorsConfiguration corsConfiguration = new CorsConfiguration();
     
            // 1 配置跨域
            // 允许所有头进行跨域
            corsConfiguration.addAllowedHeader("*");
            // 允许所有请求方式进行跨域
            corsConfiguration.addAllowedMethod("*");
            // 允许所有请求来源进行跨域
            corsConfiguration.addAllowedOrigin("*");
            // 允许携带cookie进行跨域
            corsConfiguration.setAllowCredentials(true);
            // 2 任意路径都允许第1步配置的跨域
            source.registerCorsConfiguration("/**",corsConfiguration);
            return new CorsWebFilter(source);
        }
    }

使用nginx部署为同一域 或者 在响应头中添加参数

在这里插入图片描述
10、怎样保证redis和mysql数据库同步

1、先更新数据库,再更新缓存(即删除缓存),但是有可能因为网络抖动导致删除缓存失败,这个时候可以使用重试策略,对这个删除操作进行补偿
2、采用canal订阅bing.log文件的形式

11、缓存穿透、缓存击穿、缓存雪崩发生的原因和解决方案
缓存穿透产生的原因?
查询的时候不断使用非法参数,导致缓存查询不到,数据库也查询不到,这样就会一直访问数据库,给数据库造成压力
如何解决?

1、缓存空对象:使用非法参数查询的时候,第一次会访问数据库,并把一个空对象存入缓存中,那么下一次查询就会查询缓存了
缓存空对象解决的弊端:只是针对同一个非法参数不能进行多次查询走到数据库,但是换一个非法参数还是能走数据库,而且会造成缓存有大量的空数据

在这里插入图片描述

2、布隆过滤器:底层使用的是一个位数组,一个数据会进行多次哈希落在数组的多个下标上,只要一个下标位置对应不上就绝对不存在,但也会存在哈希碰撞的情况(假如一个数据哈希之后刚好那些位置都被占用)存在一定的误判率,他的误判率大小取决于维数组的长度和哈希函数的数量
引申:项目中实现就把数据库需要查询数据的字段(比如id)放入布隆过滤器,分布式项目使用redis实现布隆过滤器,单体使用第三方的工具包

在这里插入图片描述在这里插入图片描述
缓存击穿产生的原因?
热点数据在缓存中的key过期了,这个时候又有大量的请求并发来访问,就会直接打在数据库上
缓存击穿解决方案

1、热点数据永不过期
2、加锁(双重校验锁),先放第一个请求进去查询数据库把数据同步redis中,后面的请求全部查缓存

缓存雪崩产生的原因?
机器宕机、大部分缓存key同一时间过期
缓存雪崩的解决方案?

1、高可用集群 rediscluster
2、设置过期时间错开

12、redis分布式锁

应用场景: 分布式中跨JVM进程,JVM中的锁无法锁住不同服务JVM资源
在这里插入图片描述
如何使用redis实现分布式锁?

利用redis的setnx互斥命令,set同一个key,执行成功返回1,执行失败返回0
释放锁只需要删除key

实现过程中有哪些坑?

1、死锁:setnx之后,还未来的及删除key,服务器宕机了,导致后面的线程永远进不来
解决:给这个锁的key设置一个过期时间,超时自动释放
2、设置过期时间原子性:setNx命令必须和设置过期时间命令保证原子性,否则在设置过期时间之前服务挂掉也可能造成死锁;
解决:新版本redis实现了一行命令setnx+过期时间,也可以通过lua脚本保证原子性
3、释放别人的锁:线程1先拿到锁,业务阻塞超过锁的过期时间,这是第2个线程进来拿到锁正在执行业务,这个时候线程1醒了执行完业务,直接把锁删掉,这时线程3就进来了,和线程2业务冲突,就相当于2个线程都拿到了锁,在执行业务
解决:释放锁之前先判断是不是自己的锁,可以在获取锁时存入线程标识(UUID表示),释放锁时先判断线程标识是否一致,如果一致释放锁,不一致不释放
4、锁的判断和释放必须原子性:如果线程1在判断成功后发生了线程阻塞,等到锁超时自动释放,这时候线程2进来执行业务,这时候线程1把锁删掉,线程3进来,又和线程2业务冲突
解决:使用lua脚本把锁的释放和过期放在脚本里面,在java中执行脚本
5、业务还未执行完锁过期了
解决:需要重试给锁续期

解决方案?

综上所述,利用redis的setnx命令会存在很多问题,使用redisson客户端的分布式锁,可以解决上面的问题

在这里插入图片描述
在这里插入图片描述

13、消息队列

为什么要使用消息队列?(消息队列的应用场景)

1、消息队列的本质是一种先进先出的数据结构,主要思路是投递消息到队列中,消费者监听这个队列。
2、常见的应用场景:解耦、异步、削峰

在这里插入图片描述

解耦:比如在电商系统中的下单业务,可能要同时调用支付系统、库存系统、物流系统,这个时候库存系统暂时下线了,如果不使用mq的话,系统之间的耦合太高,导致整个系统不可用,如果使用mq,下单只需要将消息发送到mq就直接返回给用户,如果库存系统这个时候上线了,他就会去消费这个消息,执行扣减库存的操作,就提高了系统的可用性。
在这里插入图片描述

异步:比如用户在注册成功之后会给用户发短信,如果按照同步的去执行的话,就比较耗时,需要等到短信发送成功才能得到响应,如果使用mq,用户注册之后,把消息发送给mq之后就可以直接响应。然后短信服务再去监听mq,异步的发送短息,大大提高了响应速度。
在这里插入图片描述

削峰:比如像双11那种秒杀场景,可能同一个时间很多请求进来,导致数据库压力过大,可能就崩了,比如用户的请求是每秒5K个,而我数据库只能承受每秒2K个,那么这个时候就可以使用mq对这些流量削峰,可以把这5K个请求全部放在mq中,那么我的系统从MQ中每秒拉取2K个请求消费,这个时候请求会执行个2.5s,但总比系统挂了好。

各种消息队列产品的比较?
在这里插入图片描述如何保证消息不丢失?

在这里插入图片描述
在这里插入图片描述
ps:如果MQ在消息持久化的过程中宕机了,消息就真丢了,所以要保证MQ,高可用使用集群。

如何保证消息的幂等性?(消息不被重复消费)

在这里插入图片描述
如何保证消息的顺序消费?
在这里插入图片描述

发送消息:
在这里插入图片描述消费消息:

在这里插入图片描述如何使用MQ来解决分布式事务?

在这里插入图片描述14、分布式事务解决方案
分布式事务为什么会产生?

本质是跨JVM进程,跨JDBC连接,都会产生分布式事务,那么会有以下三种情况:
1、单体项目配置了多个数据源,就有多个JDBC连接,跨JDBC连接
2、微服务项目多个服务对应一个数据库,跨JVM进程
3、微服务项目,每一个服务都有一个数据库,既跨JVM进程,也跨JDBC连接
这些情况都会产生分布式事务

解决的思想?

基于CAP理论和Base理论,分布式事务大都采用最终一致性的思想来实现

C-Consistency(一致性)
在这里插入图片描述A-Availability(可用性)
在这里插入图片描述P-Partition tolerance

在这里插入图片描述
组合方式
在这里插入图片描述Base理论

在这里插入图片描述
在这里插入图片描述
解决方案?
https://zhuanlan.zhihu.com/p/183753774

数据库层面:
强一致性:2pc、3pc
业务层面:
强一致性:tx-lcn框架的lcn模式
最终一致性:本地消息表+消息队列+定时任务、事务消息、最大努力通知、Seata框架的AT模式、TCC、Tx-lcn框架的txc模式

在这里插入图片描述

15、mybaties的二级缓存

一级缓存:sqlSession(java客户端跟数据库的一次连接),在同一次sqlSession会话中,第二次查询SQL语句+入参 完全一样的话会走缓存,mybaties默认开启了一级缓存
二级缓存:默认开启namspce为单位(mapper.xml)为单位,为所有sqlSession和多个线程共享,mybaties默认关闭二级缓存
一级缓存命中条件:对于调用接口而言,每次调用都会创建一个sqlSession连接数据库,开启事务,提交事务,然后关闭sqlSession连接,如果多个请求同一个事务中,那么多个请求都在共用一个SqlSession,反之每个请求都会创建一个SqlSession;
引申:所以一般在写业务代码时,很少有命中mybaties的业务,这也是为什么有了mybaties的缓存还要使用redis缓存

在这里插入图片描述

16、多线程、线程池

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述volatile关键字的作用:保证多线程下命令执行的可见性、有序性;volatile关键字可以保证内存可见性和有序性,但不能保证原子性
![在这里插入图片描述](https://img-blog.csdnimg.cn/4aa0a5b388f2471689ba6af6239ca0ed.png

17、JVM和垃圾回收

在这里插入图片描述

18、其他知识:
select…for update 使用到索引会锁行,没是用到索引会锁表;

索引

多线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值