1.三次握手中,最后一次回复丢失,会发生什么?
答:客户端第三次丢失是感应不到的,所以,会当作正常情况发送报文,Server端将以RST
包响应要求,此时,客户端知道,第三次握手失败。而服务器经过一段时间后,没有得到第
三次握手的响应,则重新发送第二次握手的包。默认为5次重发。间隔时间为3,6,12秒,
之后就放弃。
2.消息队列的确保机制:
答:
-发送端的可靠性
发送端完成操作后一定能将消息成功发送到消息队列中。
实现方法:在本地数据库建一张消息表,将消息数据与业务数据保存在同一数据库实例里,
这样就可以利用本地数据库的事务机制。事务提交成功后,将消息表中的消息转移到消息队
列中,若转移消息成功则删除消息表中的数据,否则继续重传。
-接收端的可靠性
接收端能够从消息队列成功消费一次消息。
两种实现方法:
保证接收端处理消息的业务逻辑具有幂等性:只要具有幂等性,那么消费多少次消息,最后
处理的结果都是一样的。
保证消息具有唯一编号,并使用一张日志表来记录已经消费的消息编号。
3. redis高并发的原因:
答:
-它是单线程,没有进程竞争,锁等设置,所以少了切换上下文的时间,相对快了很多。
-同时,数据存储在内存中,他可以快速处理数据。
-同时,它又是epoll的多路复用模式,异步的读取信息,自己要进行的逻辑处理也相对很
少。并且可以涉及单机多redis,充分利用其他cpu核心。
4. threadlocal的作用:
答:确保线程中有独享的变量副本,可以为自己服务。这类副本本身是不用多个线程维护状
态的。所以可以放入线程本地。
5.微服务注册中心,如何主动删除服务?
参考:https://blog.csdn.net/xiaobao5214/article/details/81263445?utm_source=blogxgwz1
答:
- 一个是客户端自己关闭后,eureka检查心跳,发现服务已经下线就关闭。
-一个是发送delete 请求:/eureka/apps/app-name到注册中心。
-
还有就是客户端如果是springboot,那么调用方法
DiscoveryManager.getInstance().shutdownComponent();即可。
6. http状态码,及其对应的304状态码的含义:
答:客户端在请求一个文件的时候,发现自己缓存的文件有Last Modified(截止时间),
那么在请求中会包含If Modified Since,这个时间就是缓存文件的Last Modified。因此,
如果请求中包含If Modified Since,就说明已经有缓存在客户端。服务端只要判断这个时间
和当前请求的文件的修改时间就可以确定是返回304还是200。返回304,则代表浏览器
可以继续使用缓存数据。如此,可以减少传输的数据量,同时,服务器也不需要进一步执行
相关数据的查询。
7. 两种数据库引擎的差异答:6大差别:
- Innodb 支持行级锁,和外键,myisam不支持行级锁和外键。
- innodb删除表的数据是一行一行的删除的,而myisam是直接删除一个表。
- innodb表中,没有缓存这个表的数量(即count(*));而myisam缓存了。
- innodb支持事务,而myisam不支持。
- innodb的存储文件是一个大文件,而myisam是三个文件,分别存储数据,索引,表的定
义。在迁移数据库的时候更加方便。
- 5.6 之前,InnoDB 不支持全文索引,MyISAM支持全文类型索引
8. b+树的优点:
答:
-数据均存储在叶子节点中,非叶子节点只有索引值。这样的设置,非叶子节点小,一次性
读入内存的节点多,io新能消耗低。
- B+树的查询效率更加稳定,路径长度一致。
- B+树的数据都存储在叶子结点中,各个叶子节点有兄弟指针,所以,扫库的时候很方便,
只需要扫一遍叶子结点即可。
9.聚簇索引的特点:
https://blog.csdn.net/qq_29373285/article/details/85254407
https://www.cnblogs.com/wangkaihua/p/10220462.html
答:索引的位置和其对应的物理内存顺序是一致的,即,索引排在前的,其数据存储的物理
地址也在前面。同时,聚簇索引的叶子节点就是数据,而非聚簇的叶子节点是主键id,还要
根据这个id去对应的聚簇索引中查询相关的数据。
9.复合索引的最左原则
答:最左匹配四个点:
- 建立一个复合索引(a,b,c),相当于建立了多个索引(a),(a,b),(a,b,c);
-索引排序是根据从左向右匹配的。
-查询的时候,优化器会优化sql 语句为对应索引的顺序,即:(a,c,b)也是可以用索引的。
-单独查询b,会采用index类型索引,即:不符合最左,直接查询所有的节点,找到对应
的数据指针,回表,这样很慢。
补充:复合索引的三个好处:可以减小索引树的个数,节省空间开销,建立一个树,相当于
建立三棵树。可以提高效率,索引越多,筛选出的剩余数据越少,回表的时候越快。可以实
现覆盖索引。即:查询的数据刚好是我们的树的索引项,比如就要找(a,b,c),那么就可以
不用回表,返回索引的数据即可。
10. springmvc的过程:https://www.cnblogs.com/fengquan-blog/p/11161084.html
答:
-请求给dispetchServlet 拦截,dispetchServlet注册handlerMapping。
-转发(调用自己的成员变量)给handlerMapping对象,它根据配置文件,初始化自己的值。
其中有个自己维护的一张map《url,bean》,根据拦截到的url的路径,可以找到对应的
controller对象,封装为HandlerExecutionChain(里面可能还有一些拦截器,面向切面那种)。
返回给dispetchServlet。
- dispetchServlet转发HandlerExecutionChain给适配的handlerAdapter(也是dispetchServlet
自己注册维护的,默认有三种适配器)。
- handlerAdapter根据接收到的controller(也是handler)的类名,利用反射,执行其handle
方法。(如果有拦截器,会先执行pre拦截器,而后是handler的方法,之后是post拦截器。这些拦截器好像都是动态代理前织入的)返回modelandview给dispetchServilet。
- dispetchServilet转发modelandview给viewResolver;
- viewResolver将modelAndView找出,这里其实也是一个map 映射过程。modelAndView
只是一个包含model 数据和页面名字字符串的对象。viewResolver根据这个字符串去到配置
的路径,如resource之类的地方,找到对应的jsp页面。然后返回具体的view对象给
dispetchServilet。
- dispetchServilet调用对象View的方法renter()。该方法将model注入到jsp中(其实是
装入了response的请求头里),然后返回。
- dispetchServilet将视图返回给浏览器。
11.分布式锁的实现原理:
答:三个:
-利用mysql
-利用redis的setnx实现
-利用redis集群算法RedLock
12.为什么用线程池不用new?
答:1、每次new Thread,新建对象性能差2、缺乏统一管理,可能导致线程创建过多,死
机等。3、缺乏更多功能,如:定时执行,定期执行,线程中断等。
13.为什么线程池不允许使用Executors去创建?
答:推荐使用threadPoolExecutor,因为executors其实就是对threadPoolExecutor的一个封
装。而且封装的不好,它允许创建的最大线程是maxint,很容易导致oom,内存不足错误。
所以,创建线程池,还是要我们自己手动通过threadPoolExercutor设置参数。
- newFixedThreadPool和newSingleThreadExecutor:是等待队列无限长
- newCachedThreadPool和newScheduledThreadPool:是最大线程数无限长
14. get和post 的区别,get的最长数据段是?
答:
- get主要是为了获取数据,而post是为了提交数据。两者虽然都有给服务器传输数据的功
能,但是意义是不一样的。
- get拼接在url 后,post的数据放入body的param内
- GET的目的是是读取,所以,服务器对应的接口应该有幂等性。即:多次请求的数据,不
会因为我的get改变。同时,因为幂等,所以就可以对GET请求的数据做缓存。
- get在url上传递参数,默认是ascii,不支持中文,要经过其他配置,而post内的编码可以
是unicode-8,支持中文。
- URL的最大长度是2083 个字符,path的部分最长是2048个字符。不过其实是ie8规定的,
http协议没有这一点。
15. redis的5大数据结构和其底层实现,还有应用场景
答:
16. url的解析过程。
答:四个步骤;
-如果本机刚刚联网,则会去通过DHCP协议,发送广播,目标地址是67,源地址端口是
68。获得即插即用的本机的ip地址和距离本机最近的DNS服务器的ip,以及网关路由的ip。
-而后是解析浏览器的url。由于我们只知道网关路由器的ip,所以要通过ARP协议解析网
关ip,获得mac 地址。-得到后,继续进行url的解析。通过发送url给网关路由,再由路由转发到对应的DNS服
务器(DNS服务器的端口号是53),DNS服务器再通过域名解析,找到对应url的ip地
址。
-而后,浏览器可以根据DNS返回的ip,进行tcp/ip 协议,三次握手过程建立连接。(80
端口)
-最后是双方通信,服务器返回web页面信息,浏览器渲染并且显示。
17.浏览器会对html做什么?
答:渲染。
18. java的启动过程。(类的加载)https://www.cnblogs.com/qiumingcheng/p/5398610.html
答; 1. 编译,2.类的加载(5 个步骤),3.执行程序输出结果。
19. mybatis的启动过程:https://www.cnblogs.com/ZhuChangwu/p/11741125.html
答:
-通过sqlsessionFactory类注册xml配置文件(数据库的url之类的);
- sqlsessionFactory调用方法,获得sqlsession类。这个类封装了和数据库的连接,还有一系
列的事务管理功能;
- 而后,session内,有方法可以通过scan扫描到配置文件,生成mapperProxy对象;该对
象将读取对象的xxxMapper.xml文件和对应的xxx接口。采用动态代理方法,生成一个接口
实现类。
-执行sql语句时,通过反射的方式,调用实现类的方法,其中有两个参数,对应的方法名
和sql语句。这由mapperMethed对象进行封装。
- mapperMethed传入sqlsession内封装的CRUD方法,内有对应的执行器类Executor;
-执行器类将调用方法query(),取出mapperMethed内的sql语句,生成prepareStatement。
-最后,像执行jdbc一样,进行数据库查询。
总结:mybatis,其实就是封装了jdbc。只不过,采用了动态代理,将接口和方法实现拆分
开来。
20. springboot的启动过程。
答:
- new了一个SpringApplication对象,使用SPI技术加载加载ApplicationContextInitializer、
ApplicationListener接口实例
-调用SpringApplication.run()方法
-调用createApplicationContext()方法创建上下文对象,创建上下文对象同时会注册spring
的核心组件类(ConfigurationClassPostProcessor 、AutowiredAnnotationBeanPostProcessor
等)。
-调用refreshContext()方法启动Spring容器和内置的Servlet容器
21. springboot如何启动mybatis:https://www.cnblogs.com/nxzblogs/p/10484281.html
答:
-和上面启动spring一样,在refreshContext()方法调用后,会去将加载进来的各种配置
进行处理,装入我们的springboot容器中,包括了spring,和mybatis。mybaitis的具体过程,
其实就是19的过程,只不过最后把sqlsessionFactory放入了容器中。
21. jva的gc标记算法,以及为什么不用标记计数算法?
答; gc标记算法有两个:一个是标记计数算法,有一个对象引用,就标记一次。但是,在两
个对象出现循环引用的情况下,此时引用计数器永远不为0,导致无法对它们进行回收。
第二个是可达性分析算法:即: 判断栈和方法区中是否有该对象的引用,没有,则回收。(标记计数法中,存在的问题是,堆对象和堆对象之间互相计数+1了,但是,栈中使用引用以
及被释放,比如方法已经结束了,但是,没有进行-1操作,所以存在无法回收)
22.转发和重定向的区别:
答:转发就是服务器中,一个servlet对这个请求进行了处理,但是,没有返回,而是给了
服务器另一个sevrlet再加工,而后返回。这个过程,请求头和响应头用的都是同一个。里
面的协议,编码,数据都不改变。即:两个servlet间是实现了通信。
重定向就是客户端发送信息,到达了服务器,而后服务器接处理了请求后,返回消息给浏览
器,并且告诉他,还要进行后续的操作,返回状态码为301,浏览器立即进一步发送请求。
这个过程是两次请求,而非servlet之间的通信。
表现是:浏览器上的url的改变,转发并不会改变。
23.数据库中的乐观锁和悲观锁
答:我只是说了一下定义,面试官表示,不是要原理,而是实现。
定义就是:悲观锁是认为冲突会发生,所以加了锁,乐观锁是认为,冲突一般不会发生,会
在完成业务逻辑后,在提交之前进行验证。
悲观锁我们数据库可以依靠自带的XS锁实现。
乐观锁,我们采用CAS和vesion(或者时间戳)来实现。这就需要代码上进行一定的处理了。
比如,我们可以多加一个字段vesion,读取数据的时候,将vesion读取出来,保存前,进行
比较version值,没有改变,则version+1后,再存入我们真正操作的数据。如果version改
变了,那就代表,这个数据已经过期,则要重新来一遍了。
全部评论
(0) 回帖