2023java面试题
1.微服务是什么
微服务是一种分布式架构,分布式架构就是把服务拆分。在传统单体架构中,我们把所有服务都写在一起,随着业务的扩大我们的代码耦合度越来越高,后期维护起来也比较不方便。
微服务就是把模块拆分,把我们的项目分离成多个子项目,每个子项目之间独立开发部署,子项目也有自己独立的功能,这些独立的子项目就形成了微服务,不同的子项目就形成了一个微服务集群。
2.分布式事务
在了解分布式事务之前,先了解事务的概念,事务一般指的是数据库事务,具有4个特性:原子性、一致性、隔离性、持久性。
原子性:单个事务执行,要么成功,要么失败
一致性:事务运行前后的完整性必须保持一致
隔离性:防止事务并发执行
持久性:事务结束后不会丢失
数据库事务有这4个特性,分布式事务也不例外。
在微服务架构下,服务之间通过RPC远程调用。对于单机事务来说,多了网络通信这一不确定因素,原来有成功失败两种结果,现在变成成功失败未知3种结果。分布式事务就是在这种不确定性通信下实现的事务特性。网络波动,容易导致信息丢失,机器宕机,消息乱序,信息错误,不可靠的tcp.
分布式事务的方案:
2PC、3PC。
2PC是一种协议,它的作用保证在分布式系统中每个节点要不都提交事务,要么都取消事务。3PC引入超时机制来解决2PC的同步阻塞问题。
3.mysql和oracle中的事务隔离级别区别
mysql事务自动提交,mysql中的innodb支持事务
orcale使用commit手动提交事务。
1、脏读
脏读是指在一个事务处理过程里读取了另一个事务未提交的数据。
2、不可重复读
不可重复读:一个事务中多次查询时结果不一样,这是由于在查询间隔,被另一个事务修改并提交了
3、虚读(幻读)
幻读是事物中一种非独立的现象,幻读和不可重复读都是读取已提交的数据
mysql有4种隔离级别
可重复读(默认):可避免脏读、不可重复读的发生
读未提交 :最低级别,任何情况都无法保证
读已提交 :可避免脏读
串行化:可避免脏读、不可重复读、幻读的发生。
oracle存在两种隔离级别
读已提交(默认),可避免脏读
串行化:可避免脏读、不可重复读、幻读的发生。
oralce不会出现脏读,天生读写不阻塞。
没有并发就没有锁,在事务中隔离级别越高,效率越低。
orcale,mysql的区别
1、MySQL有自增型主键,创建表的时候可以通过指定auto_increment实现主键自增。Oracle没有自增型主键,一般通过序列实现。
2、MySQL默认的事务隔离级别是可重复读,而Oracle默认是读已提交。
3、MySQL在存储引擎是MyISAM的时候是不支持事务的,存储引擎是InnoDB的时候才支持事务,而Oracle都支持事务。
4、MySQL的字符串是用双引号包着,而Oracle用的是单引号。
5、MySQL和Oracle都用group by进行分组,而Oracle使用group by 的时候,select查询的字段必须包含group by 使用到的字段,不然就会报错。
6、MySQL使用limit进行分页,而Oracle没有limit,需要用rownum和嵌套查询实现分页。
7、MySQL中有null值和空字符串,而Oracle中只有null值,没有空字符串。
8、MySQL日期格式转换是用Date_format( ,‘%Y-%m-%d’),而Oracle用to_char( ,‘yyyy-mm-dd’)或者to_date
4.线程的创建方式
1)继承Thread类创建线程
public class MyThread extends Thread{//继承Thread类public void run(){//重写run方法}
}
public class Main {public static void main(String[] args){new MyThread().start();//创建并启动线程}
}
2)实现Runnable接口创建线程
public class MyThread2 implements Runnable {//实现Runnable接口public void run(){//重写run方法}
}
public class Main {public static void main(String[] args){//创建并启动线程MyThread2 myThread=new MyThread2();Thread thread=new Thread(myThread);thread().start();//或者 new Thread(new MyThread2()).start();}
}
3)使用Callable和Future创建线程
public static class MyThread3 implements Callable<Integer> {@Overridepublic Integer call() throws Exception {return 15 + 16;}}
public class Main {public static void main(String[] args) {MyThread3 th = new MyThread3();//使用Lambda表达式创建Callable对象, FutureTask类来包装Callable对象/*FutureTask<Integer> future = new FutureTask<>(() -> 5 + 6);*/FutureTask<Integer> future = new FutureTask<>(new MyThread3());//实质上还是以Callable对象来创建并启动线程new Thread(future, "有返回值的线程").start();try {//get()方法会阻塞,直到子线程执行结束才返回System.out.println("子线程的返回值:" + future.get());} catch (Exception ex) {ex.printStackTrace();}}
}
4)使用线程池例如用Executor框架
线程池的创建的4种方式
newCachedThreadPool创建可缓存线程池、
newFixedThreadPool创建定长线程池、
newScheduledThreadPool创建定长线程池、
newSingleThreadExecutor创建单线程化线程池。
5.Spring的生命周期
普通new一个对象无引用时会被垃圾回收机制回收,而由IOC托管的对象,由spring生命周期容器控制。
Spring的生命周期,就是bean的生命周期,从bean开始装载,默认已单例实例化。
1、实例化bean(调用构造方法)
对于BeanFactory容器,当客户向容器请求时(bean此时未初始化),需要注入另一个未初始化依赖。容器调用createBean进行实例化
ApplicationContent容器,启动结束,便实例化所有的bean
BeanDefinition对信息实例化
BeanWrapper设置对象属性接口(避免使用反射器)
2、属性注入
设置依赖对象(依赖注入)实例化对象被封在BeanWrapper中,Spring根据BeanDefinition中信息进行依赖注入,注入Aware接口:Spring会检测对象是否实现Aware接口,将Aware实例注入给bean
BeanPostProcessor对象自定义处理
3、初始化bean(有多种方式可以指定bean的初始化方法,如init方法)
initializingBean init-method
DisposableBean destroy-method
4、使用
5、销毁
总结:实例化bean—》注入属性—》调用init—》bean可用了—》销毁
6.zuul网关
统一入口:未全部为服务提供一个唯一的入口,网关起到外部和内部隔离的作用,保障了后台服务的安全性。
鉴权校验:识别每个请求的权限,拒绝不符合要求的请求。
动态路由:动态的将请求路由到不同的后端集群中。
减少客户端与服务端的耦合:服务可以独立发展,通过网关层来做映射。
(ip白名单,routes路由配置)
7.对redis的理解
redis是一个高性能的基于Key-Value结构存储的NoSQL开源数据库。大部分公司采用Redis来实现分布式缓存,用来提高数据查询效率。
redis是单线程应用程序,占用内存较少,防止多线程相互竞争CPU带来上下文切换,无锁操作性能更高,相对而言对硬件成本相对低廉。
redis五种类型:string(字符串),hash(哈希),list(列表),set(集合),sort set (有序集合)
redis支持分布式集群,磁盘持久化:第一种持久化方式RDB 存在磁盘上,每隔一段时间进行持久化操作。第二种是AOF ,把指令记下来,下次启动再重复执行,每次进行命令都会持久化。
redis中缓存穿透、雪崩、击穿
① 缓存穿透:大量请求根本不存在的key
② 缓存雪崩:redis中大量key集体过期
③ 缓存击穿:redis中一个热点key过期(大量用户访问该热点key,但是热点key过期)
穿透解决方案:
① 缓存穿透:
对空值进行缓存
设置白名单
使用布隆过滤器
网警
②雪崩解决方案:
进行预先的热门词汇的设置,进行key时长的调整
实时调整,监控哪些数据是热门数据,实时的调整key的过期时长
使用锁机制
③击穿解决方案:
进行预先的热门词汇的设置,进行key时长的调整
实时调整,监控哪些数据是热门数据,实时的调整key的过期时长
使用锁机制(只有一个线程可以进行热点数据的重构)
8.为什么使用消息队列,使用消息队列的好处
为什么使用消息队列
异步处理,流量控制,服务解耦
https://zhuanlan.zhihu.com/p/480260300
消息队列数据丢失怎么办
丢消息的关键点有3个:
Producer 发送消息的过程
消息队列的消息存储
Consumer 消费消息的过程
https://blog.csdn.net/weixin_45994575/article/details/123454288
数据被重复消费了咋办
保证消息不被重复消费的关键是保证消息队列的幂等性
(幂等性一般指 producer 投递了多少消息,consumer 就消费了多少消息,不会发生消息丢失或者消息重复的情况)
https://blog.csdn.net/cy562086345/article/details/117568780
一个请求,请求了10次,2次错的,8次对的怎么排查。
索引类型有啥,
一个程序掉进后端了打印log了卡住了咋办
9.有关SqlSessionFactory
SqlSessionFactory一旦被创建,应该在应用执行期间都存在.在应用运行期间不要重复创建多次,建议使用单例模式.SqlSessionFactory是创建SqlSession的工厂.
10.java虚拟机
java虚拟机是一种抽象化的计算机,通过在实际计算机上仿真模拟各种计算机功能来实现的。jvm有自己完善的硬件结构,处理器,堆栈,寄存器,指令系统。jvm屏蔽了OS相关信息,使java程序只需生成在java虚拟机上运行的目标代码,就可以在不同平台上修改。
jvm从程序到源码的3个步骤: .java文件,class文件,机器码
11.java内存模型
java采用共享内存并发模型,主内存+多个工作内存
https://blog.csdn.net/bbj12345678/article/details/120303136
11.做过的项目难点
定时任务,a.b服务器都有,Redis做了锁的配置
xxljob是有的这个锁的控制机制的