最近开始找工作了,坐标杭州。渣渣感觉面试应该挺困难的,也不知道具体会问哪些类型,会在面试完把每一次面试问到的题目列出来, 一个作用是参考记录,另一个作用是可以把自己不会或者弱项的问题及时补齐。
暂时是先把问题列出来,有时间的时候会把答案补上。
希望能找到一个好工作,加油
我大概总结一下,小型公司2年以下开发主要业务就是CRUD,招人肯定是希望能立马上手,所以面试范围我押题是常用的框架(SpringBoot、Spring基本概念,Mybatis),事务、数据库相关(锁、事务级别、sql优化,数据库底层概念等)、异常。有些会问一些设计模式(主要掌握工厂模式、单例模式、代理模式。)。
中大型公司的话,加上 JVM,集合,并发编程,一些网络知识。有些可能还会有一两道算法题。甚至开始问分布式了,具体看他们业务。
大厂请直接参考我画的java路线图,大厂知识路线没有3年以下之分,只有深/广度之分:Java知识体系脑图(2020年)
第一家银行相关业务,需要频繁出差的公司 远程电话面试。
(PS:面试官喜欢在别人说话的时候发出各种语气词,多次打断思路…)
第一环节:自我介绍,介绍一下自己的基本情况。
第二环节:开始面试。
目前应该学习的技术和框架发在我的博客了:Java知识体系脑图(2020年)
略
工厂模式、单例模式、代理模式、观察者模式、适配器模式、责任链模式、装饰者模式。
工厂模式、单例模式、代理模式。
所谓设计模式,就是在特定的情况下,应该使用的经过验证的有效的办法。需要根据场合来使用相应的设计模式。
单例模式:SpringMVC中有,默认bean是singleton。保证类只有一个实例。
工厂模式:类的创建依赖工厂类,SpringMVC中的bean工厂。
代理模式:Spring的AOP。
适配器模式:SpringMVC的handler使用了适配器模式。Springmvc创建了一个适配器接口,接口下有每个handler的适配器实现类,这样在扩展controller的时候,增加一个适配器就行。这样,前端控制器只需要调用处理器适配器即可。剩下的事情交给处理器适配器去适配。
装饰模式:io流。过滤流BufferedInputStream去装饰节点流(fileIuputstream)。
工厂设计模式是一种创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
1.静态工厂模式(简单工厂模式)。工厂类是整个模式的关键所在,包含了必要的逻辑判断,能够外界给定的信息, 决定究竟创建哪个具体类的对象。
2.普通工厂模式(工厂模式)。工厂方法模式 是对简单工厂方法模式的一个抽象,抽离出了一个Factory类(或者接口),这个接口不负责具体产品的生产,而只是指定一些规范,具体的生产工作由其子类去完成。这个模式中,工厂类和产品类往往是一一对应的,完全解决了简单工厂模式中违背“开闭原则”的问题,实现了可扩展;
3.抽象工厂模式。抽象工厂模式 的特点是存在多个抽象产品类,每个抽象产品类可以派生出多个具体产品类,工厂提供多种方法,去生产“系列”产品。
简单(静态)工厂模式适用于工厂类需要创建的对象比较少的情况,客户只需要传入具体的参数,就可以忽略工厂的生产细节,去获取想要的对象;(普通)工厂方法模式,主要是针对单一产品结构的情景;抽象工厂模式则是针对多级产品结构(系列产品)的一种工厂模式。
SpringCloud早期体系是NetFlix旗下的,由于部分组件的停止维护,现在主要使用的是Alibaba旗下的。
SpringCloud Netflix:Eureka 服务发现与注册(停止维护)、Ribbon 负载均衡、Feign 负载均衡、Hystrix 服务熔断(停止维护)、Zuul 路由网关;
SpringCloud Alibaba:Nacos 注册中心、Ribbon 负载均衡、Feign 负载均衡、Sentinel 服务熔断、Gateway 路由网关。
JVM调优即调整其中的各项参数,让JVM的效率更好。常常操作的就是堆中各区域的大小、影响对象回收效率的参数、GC参数。
部分调优参数:
参数 | 说明 |
---|---|
-Xms | 设置初始 Java 堆大小,单位默认是字节,可以使用k,m,g |
-Xmx | 设置最大 Java 堆大小,单位默认是字节,可以使用k,m,g |
-Xmn | 设置新生代的初始值和最大值,单位默认是字节,可以使用k,m,g |
-Xss | 设置 Java 线程堆栈大小,单位默认是字节,可以使用k,m,g |
-XX:NewRatio | -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5;若Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。 |
-XX:SurvivorRatio | 默认-XX:SurvivorRatio=8,即伊甸区Eden与2个幸存区Survivor比值为8:1:1,一个Survivor区占整个年轻代的1/10 |
-XX:MaxTenuringThreshold | 默认-XX:MaxTenuringThreshold=15,即新生对象的存活年龄,经过多少次Mirno GC才会进入永久代;如果设置为0的话,则年轻代对象不经过Survivor区,该参数只有在串行GC时才有效。 |
crud,根据自己实际业务说明。
首先,说说什么事务。我认为事务,就是一组操作数据库的动作集合。
Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。
最好不要在程序中同时使用上述三种事务类型;并且,事务要在尽可能短的时间内完成,不要在不同方法中实现事务的使用。
1、JDBC事务
public String delete(String id) {
String ID = id;
db = new getConnection();
Connection con = db.getConnection();
try {
con.setAutoCommit(false);
db.executeUpdate("delete from helloworld where ID=" + ID); //更新操作1
db.executeUpdate("delete from helloworld _book where ID=" + ID); //更新操作2
db.executeUpdate("delete from helloworld_user where ID=" + ID); //更新操作3
con.commit();//提交JDBC事务
con.setAutoCommit(true);
db.close();
return “success”;
}
catch (Exception e) {
con.rollBack();//回滚JDBC事务
e.printStackTrace();
db.close();
return “fail”;
}
}
2、JTA事务
JTA是J2EE事务服务的解决方案、描述了J2EE模型事务接口。JTA具有三个主要的接口:UserTransaction、TransactionManager、Transaction接口。这些接口共享公共的事务操作,如:commit()、rollback()。同时各自也有自己的操作。举例说明:
public String delete(String id) {
String ID = id;
db = new getConnection();
db.getConnection();
UserTransaction transaction = sessionContext.getUserTransaction();//获得JTA事务
try {
transaction.begin(); //开始JTA事务
db.executeUpdate("delete from helloworld where ID=" + ID);
db.executeUpdate("delete from helloworld _book where ID=" + ID);
db.executeUpdate("delete from helloworld _user where ID=" + ID);
transaction.commit(); //提交JTA事务
db.close();
return”success”;
}
catch (Exception e) {
try {
transaction.rollback();//事务回滚
}
catch (Exception e) {
e.printStackTrace();
}
exc.printStackTrace();
db.close();
return “fail”;
}
}
3、容器事务管理
在Spring、Hibernate等框架中都有各自的事务管理功能。虽然表现形式有些差别,但都是在JAVA事务管理的基础上实现的。
Spring支持编程式事务管理以及声明式事务管理两种方式。
-1- 编程式事务管理
编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。
-2- 声明式事务管理
声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。
事务是现代数据库理论中的核心概念之一,在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。事务必须服从ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)的缩写。
MYSQL 事务处理主要有两种方法:
1、用 BEGIN, ROLLBACK, COMMIT来实现
BEGIN 开始一个事务
ROLLBACK 事务回滚
COMMIT 事务确认
2、直接用 SET 来改变 MySQL 的自动提交模式:
SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交 //在 MySQL 命令行的默认设置下,事务都是自动提交的
Mysql的四种隔离级别:
Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。
脏读(Drity Read):脏读又称无效数据读出(读出了脏数据)。一个事务读取另外一个事务还没有提交的数据叫脏读。
某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
解决办法:把数据库的事务隔离级别调整到READ_COMMITTED(读提交/不可重复读)
不可重复读(Non-repeatable read):不可重复读是指在同一个事务内,两次相同的查询返回了不同的结果。
在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
解决办法:把数据库的事务隔离级别调整到REPEATABLE_READ(可重复读)
幻读(Phantom Read):幻读也是指当事务不独立执行时,插入或者删除另一个事务当前影响的数据而发生的一种类似幻觉的现象。
系统事务A将数据库中所有数据都删除的时候,但是事务B就在这个时候新插入了一条记录,当事务A删除结束后发现还有一条数据,就好像发生了幻觉一样。这就叫幻读。
解决办法:把数据库的事务隔离级别调整到 SERIALIZABLE_READ(序列化执行),或者数据库使用者自己进行加锁来保证。
不可重复读出现多是因为修改;幻读重点是新增、删除。
在Spring Boot中使用@Transactional注解,只需要在启动类上添加@EnableTransactionManagement注解开启事务支持。
@Transactional不仅可以注解在方法上,也可以注解在类上。当注解在类上的时候意味着此类的所有public方法都是开启事务的。如果类级别和方法级别同时使用了@Transactional注解,则使用在类级别的注解会重载方法级别的注解。Spring声明式事务配置简单参考:
事务的传播性:
@Transactional(propagation=Propagation.REQUIRED)
事务的隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据(会出现脏读, 不可重复读) 基本不使用
只读:
@Transactional(readOnly=true)
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。
事务的超时性:
@Transactional(timeout=30)
回滚:
在默认设置下,事务只在出现运行时异常(runtime exception)时回滚,而在出现受检查异常(checked exception)时不回滚。
指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。
Spring事务的隔离级别
隔离级别 | 说明 |
---|---|
ISOLATION_DEFAULT | 使用后端数据库默认的隔离级别。 |
ISOLATION_READ_UNCOMMITTED | 允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。 |
ISOLATION_READ_COMMITTED | 允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。 |
ISOLATION_REPEATABLE_READ | 对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻影读仍可能发生。 |
ISOLATION_SERIALIZABLE | 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。 |
Spring事务的传播性
传播性 | 说明 |
---|---|
PROPAGATION_REQUIRED | 支持当前事务,若当前存在事务,则支持当前事务,若不存在,则另开启新的事务; |
PROPAGATION_SUPPORTS | 支持当前事务,若当前存在事务,则支持当前事务,若不存在,则以无事务的状态执行; |
PROPAGATION_MANDATORY | 支持当前事务,若当前存在事务,则支持当前事务,若不存在,则抛出异常; |
PROPAGATION_REQUIRES_NEW | 新开事务执行,若当前存在事务,则挂起当前事务; |
PROPAGATION_NOT_SUPPORTED | 以无事务状态执行,若存在事务则挂起; |
PROPAGATION_NEVER | 以非事务状态执行,若存在事务则抛异常; |
PROPAGATION_NESTED | 当前存在事务,则嵌套一个新事务,当前不存在事务,则新开事务。 |
本文答案参考:
[1]:@尼尧Nier:Java知识体系脑图(2020年)
[2] @LSZJXin :三大工厂模式的代码实现及总结
[3] @贱贱的小帅哥 :JVM调优参数汇总
[4] @香吧香 :java的事务类型及定义
[5] @全菜工程师小辉 :有关Spring事务,看这一篇就足够了
[6] 菜鸟教程 :MySQL 事务
[7] @gao_jian :mysql 四种隔离级别
[8] @vinter_he :脏读,不可重复读,幻读区别和避免
[9] @光仔December :【Spring Boot学习总结】13.Spring Boot事务控制