艰难的校招之路(Java综合面经系列二)

写在前面

之前一篇博客已经介绍了一部分面经,接下来是另一部分。之前的:计网和基础

一、Mysql数据库

关于Mysql,之前也有一篇博客:MySQL
接下来的问题如果没有详细解答,可以参考我上面的博客。

1.数据库中有哪些索引类型

  • 唯一索引:在创建唯一索引时要不能给具有相同的索引值。
  • 主键索引:在我们给一个字段设置主键的时候,它就会自动创建主键索引,用来确保每一个值都是唯一的。
  • 聚集索引:我们在表中添加数据的顺序,与我们创建的索引键值相同,而且一个表中只能有一个聚集索引。
  • 普通索引:它的结构主要以B+树和哈希索引为主,主要是对数据表中的数据进行精确查找。
  • 全文索引:它的作用是搜索数据表中的字段是不是包含我们搜索的关键字,就像搜索引擎中的模糊查询。

2.数据库索引底层实现

B+树

3.为什么选用B+树

4.hash索引与B+树如何选用

5.有哪些数据库引擎,各自的区别

ISAM,HEAP,BERKLEYDB,MYISAM,INNODB

6.聚集索引和非聚集索引的区别

7.怎么对一条查询语句进行调优

8.MySQL有哪几种锁,分别怎么实现

9.MySQL四种隔离级别,底层实现

10.什么情况下设置了索引但是会失效

11.数据库的三大范式

其实不止三种范式:一共有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
第一范式:域要有原子性
第二范式:基于第一范式,主键约束
第三范式:基于第二范式,外键约束

12.数据库的四大特性

ACID

13.数据库如何解决幻读

Innodb使用临键锁,防止幻读。

14.MySQL主从复制的原理

步骤一:主库db的更新事件(update、insert、delete)被写到binlog
步骤二:从库发起连接,连接到主库
步骤三:此时主库创建一个binlog dump thread线程,把binlog的内容发送到从库
步骤四:从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log.
步骤五:还会创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db.

15.MySQL的如何保证事务

  • redo log重做日志用来保证事务的持久性
  • undo log回滚日志保证事务的原子性
  • undo log+redo log保证事务的一致性
  • 锁(共享、排他)用来保证事务的隔离性

16.MVCC底层实现

Multiversion concurrency control (多版本并发控制)
Innodb是乐观的并发控制

17.Mysql的左外连接丶右外连接与内连接的区别

18.statement和preparestatement的区别

PreparedStatement继承自Statement,两者都是接口。
PreparedStatement对象不仅包含了SQL语句,而且大多数情况下这个语句已经被预编译过,因而当其执行时,只需DBMS运行SQL语句,而不必先编译。预编译可以防止Sql注入的漏洞。
Update大量的数据时, 先构建一个INSERT语句再多次的执行, 会导致很多次的网络连接.。要减少JDBC的调用次数改善性能, 可以使用PreparedStatement的AddBatch()方法一次性发送多个查询给数据库。

  1. JDBC驱动的最佳化是基于使用的是什么功能. 选择PreparedStatement还是Statement取决于你要怎么使用它们. 对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的。
  2. PreparedStatement的第一次执行消耗是很高的. 它的性能体现在后面的重复执行。使用PreparedStatement的方式来执行一个针对数据库表的查询。JDBC驱动会发送一个网络请求到数据解析和优化这个查询。而执行时会产生另一个网络请求。 在JDBC驱动中,减少网络通讯是最终的目的。如果我的程序在运行期间只需要一次请求, 那么就使用Statement. 对于Statement, 同一个查询只会产生一次网络到数据库的通讯。

19.数据库连接池

数据库连接本质就是⼀个 socket 的连接。数据库服务端还要维护⼀些缓存和用户权限信息之类的所以占用了⼀些内存。我们可以把数据库连接池是看做是维护的数据库连接的缓存,以便将来需要对数据库的请求时可以重用这些连接。为每个用户打开和维护数据库连接,尤其是对动态数据库驱动的网站应用程序的请求,既昂贵又浪费资源。在连接池中,创建连接后,将其放置在池中,并再次使用它,因此不必建立新的连接。如果使用了所有连接,则会建立⼀个新连接并将其添加到池中。 连接池还减少了用户必须等待建立与数据库的连接的时间。

20.大数据量怎么办?

当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,⼀些常见的优化措施如下:

  1. 限定数据的范围
    务必禁止不带任何限制数据范围条件的查询语句。比如:我们当⽤户在查询订单历史的时候,我们可以控制在⼀个⽉的范围内;
  2. 读/写分离
    经典的数据库拆分方案,主库负责写,从库负责读;
  3. 垂直分区
    根据数据库里面数据表的相关性进行拆分。简单来说垂直拆分是指数据表列的拆分,把⼀张列比较多的表拆分为多张表。
  • 垂直拆分的优点: 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
  • 垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
  1. 水平分区
    保持数据表结构不变,通过某种策略存储数据分片。这样每⼀片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。
    需要注意的⼀点是:分表仅仅是解决了单⼀表数据过大的问题,但由于表的数据还是在同⼀台机器上,其实对于提升MySQL并发能力没有什么意义,所以水平拆分最好分库

21.Redis

Redis也是面试中常问的考点,具体可参考我这篇博客:Redis

二、框架

我这里的框架主要是SSM,Spring boot,像SSH这样比较老的框架,这里不再介绍。

1.Spring和Springboot的区别

1、Spring Boot提供极其快速和简化的操作,让 Spring 开发者快速上手。

2、Spring Boot提供了Spring 运行的默认配置。

3、Spring Boot为通用 Spring项目提供了很多非功能性特性,例如:嵌入式 Serve、Security、统计、健康检查、外部配置等等。

2.IOC和AOP的理解

IOC控制反转,是一种思想,具体操作是DI:依赖注入,也有人说还有DL:依赖查找
AOP面向切面编程,也是一种思想。由切面和增强(通知)组成。一共分为5种通知:前置通知,后置通知,环绕通知,最终通知,异常通知。

3.AOP的底层实现

4.Spring中事务传播的各种情况

支持当前事务的情况

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建⼀个新的事务。
  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不支持当前事务的情况

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

其他情况

  • TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

5.Spring如何解决循环依赖

源码级问题,校招能问到这个问题,大厂无疑。具体可以百度,太多了,这里不解释了。

6.Spring启动流程

7.Springboot启动流程

8.SpringBoot的SPI机制是如何实现的

SPI的全名为Service Provider Interface.这个是针对厂商或者插件的。为某个接口寻找服务实现的机制
在springboot的自动装配过程中,最终会加载META-INF/spring.factories文件,而加载的过程是由SpringFactoriesLoader加载的。从CLASSPATH下的每个Jar包中搜寻所有META-INF/spring.factories配置文件,然后将解析properties文件,找到指定名称的配置后返回。需要注意的是,其实这里不仅仅是会去ClassPath路径下查找,会扫描所有路径下的Jar包,只不过这个文件只会在Classpath下的jar包中。

9.SpringMVC的工作流程

在这里插入图片描述

10.Spring Bean的注入方式

  1. 构造器注入;
  2. 设值注入(setter方式注入);
  3. Feild方式注入(注解方式注入)。

11.Spring Bean的初始化过程

在这里插入图片描述

12.Spring bean的作用域

  • singleton : 唯⼀ bean 实例,Spring 中的 bean 默认都是单例的。
  • prototype : 每次请求都会创建⼀个新的 bean 实例。
  • request : 每⼀次HTTP请求都会产生⼀个新的bean,该bean仅在当前HTTP request内有效。
  • session : 每⼀次HTTP请求都会产生⼀个新的 bean,该bean仅在当前 HTTP session 内有效。
  • global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet⼀样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

13.Spring如何实现懒加载

Spring默认会在容器初始化的过程中,解析xml,并将单例的bean创建并保存到map中,这样的机制在bean比较少时问题不大,但一旦bean非常多时,spring需要在启动的过程中花费大量的时间来创建bean 花费大量的空间存储bean,但这些bean可能很久都用不上,这种在启动时在时间和空间上的浪费显得非常的不值得。
所以Spring提供了懒加载机制。所谓的懒加载机制就是可以规定指定的bean不在启动时立即创建,而是在后续第一次用到时才创建,从而减轻在启动过程中对时间和内存的消耗。

懒加载机制只对单例bean有作用,对于多例bean设置懒加载没有意义。
具体如何实现,请自行百度,内容太多了。

14. #{}和${}的区别是什么?

  1. #{}是预编译处理,$ {}是字符串替换。
  2. MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值;MyBatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。
  3. 使用 #{} 可以有效的防止SQL注入,提高系统安全性。

15.Mybatis一级缓存和二级缓存

先写到这吧,如果大家有什么新的问题,可以留言或私聊我。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值