最新背诵版 Java 面经汇总囊括了基本所有考点(建议收藏)

RabbitMQ有以下几种工作模式 :
简单模式:一个生产者,一个消费者

work模式:一个生产者,多个消费者,每个消费者获取到的消息唯一。

订阅模式:一个生产者发送的消息会被多个消费者获取。

路由模式:发送消息到交换机并且要指定路由key ,消费者指定路由key将队列绑定到交换机

topic模式:将路由键和某模式进行匹配,此时队列需要绑定在一个模式上
RPC

String,Stringbuffer,StringBuilder的区别

String:

  • String类是一个不可变的类,一旦创建就不可以修改。
  • String是final类,不能被继承
  • String实现了equals()方法和hashCode()方法

StringBuffer:

  • 继承自AbstractStringBuilder,是可变类。
  • StringBuffer是线程安全的
  • 可以通过append方法动态构造数据。

StringBuilder:

  • 继承自AbstractStringBuilder,是可变类。
  • StringBuilder是非线性安全的。
  • 执行效率比StringBuffer高。

String s 与new String的区别

复制代码

12 String str ="whx";String newStr =new String ("whx");

String str ="whx"

先在常量池中查找有没有"whx" 这个对象,如果有,就让str指向那个"whx".如果没有,在常量池中新建一个“whx”对象,并让str指向在常量池中新建的对象"whx"。

String newStr =new String ("whx");

是在堆中建立的对象"whx" ,在栈中创建堆中"whx" 对象的内存地址。

隔离级别 脏读(Dirty Read) 不可重复读(NonRepeatable Read) 幻读(Phantom Read)
未提交读 可能 可能 可能
已提交读 不可能 可能 可能
可重复读 不可能 不可能 可能
可串行化 不可能 不可能 不可能

反射的原理,反射创建类实例的三种方式是什么

Java反射机制:

​ Java 的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法; 并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制

获取 Class 类对象三种方式:

  • 使用 Class.forName 静态方法
  • 使用类的.class 方法
  • 使用实例对象的 getClass() 方法

JDK动态代理与cglib实现的区别

  • java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler处理。
  • cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
  • JDK动态代理只能对实现了接口的类生成代理,而不能针对类
  • cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final

谈谈序列化与反序列化

  • 序列化是指将对象转换为字节序列的过程,而反序列化则是将字节序列转换为对象的过程。
  • Java对象序列化是将实现了Serializable接口的对象转换成一个字节序列,能够通过网络传输、文件存储等方式传输 ,传输过程中却不必担心数据在不同机器、不同环境下发生改变,也不必关心字节的顺序或其他任何细节,并能够在以后将这个字节序列完全恢复为原来的对象。

分布式结构,怎么保证数据一致性

  1. 规避分布式事务——业务整合
  2. 经典方案 - eBay 模式

2、数据库相关

MySQL

●SQL注入
SQL注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
1)SQL注入攻击的总体思路

​ ●寻找到SQL注入的位置
​ ●判断服务器类型和后台数据库类型
​ ●针对不同的服务器和数据库特点进行SQL注入攻击
2)应对方法
​ ●使用正则表达式过滤传入的参数
​ ●参数绑定
​ ●使用预编译手段,绑定参数是最好的防SQL注入的方法。

● 请你说明一下 left join 和 right join 的区别?

left join(左联接) :返回包括左表中的所有记录和右表中联结字段相等的记录
right join(右联接) :返回包括右表中的所有记录和左表中联结字段相等的记录

●事务是什么

​ 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。

● 数据库ACID的特性。

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

一致性指事务前后数据的完整性必须保持一致。

隔离性指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离。

持久性是指一个事务一旦提交,它对数据库中数据的改变就是永久性的,即便数据库发生故障也不应该对其有任何影响。

● 请你介绍一下,数据库的三个范式?

第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列

第二范式(2NF):首先满足 1NF,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。

第三范式(3NF):首先是满足2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况

● 请你介绍一下数据库的隔离级别

隔离级别 脏读(Dirty Read) 不可重复读(NonRepeatable Read) 幻读(Phantom Read)
未提交读 可能 可能 可能
已提交读 不可能 可能 可能
可重复读 不可能 不可能 可能
可串行化 不可能 不可能 不可能

未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。

已提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)。

可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。

串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

数据库的脏读、幻读、不可重复读

1.脏读:

指一个事务A正在访问数据,并且对该数据进行了修改,但是这种修改还没有提交到数据库中(也可能因为某些原因Rollback了)。这时候另外一个事务B也访问这个数据,然后使用了这个被A修改的数据,那么这个数据就是脏的,并不是数据库中真实的数据。这就被称作脏读。(事务A读到了事务B未提交的数据)

解决办法:把数据库事务隔离级别调整到READ_COMMITTED

即让用户在更新时锁定数据库,阻止其他用户读取,直到更新全部完成才让你读取。

2.幻读:

指一个事务A对一个表中的数据进行了修改,而且该修改涉及到表中所有的数据行;同时另一个事务B也在修改表中的数据,该修改是向表中插入一行新数据。那么经过这一番操作之后,操作事务A的用户就会发现表中还有没修改的数据行,就像发生了幻觉一样。这就被称作幻读。(事务A修改数据,事务B插入数据,A发现表中还没有修改的数据行)

解决办法:把数据库事务隔离级别调整到SERIALIZABLE_READ

3.不可重复读:

指在一个事务A内,多次读同一个数据,但是事务A没有结束时,另外一个事务B也访问该同一数据。那么在事务A的两次读数据之间,由于事务B的修改导致事务A两次读到的数据可能是不一样的。这就发生了在一个事务内两次读到的数据不一样,这就被称作不可重复读。(事务A多次读数据,事务B访问数据,A读到了B修改的数据,导致两次读到的数据不一样

解决办法:把数据库事务隔离级别调整到REPEATABLE_READ

级别高低:脏读 < 不可重复读 < 幻读

所以设置了最高级别的SERIALIZABLE_READ就不需要设置其他的了,即解决了幻读问题那么脏度和不可重复读自然就都解决了。

● 请你简单介绍一下,数据库水平切分与垂直切分

垂直拆分就是要把表按模块划分到不同数据库表中,单表大数据量依然存在性能瓶颈

水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。

通俗理解:水平拆分行,行数据拆分到不同表中, 垂直拆分列,表数据拆分到不同表中

● 请你讲讲 Statement 和 Prepared Statement 的区别?哪个性能更好?

与Statement相比,①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);②PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快

mysql数据库的索引类型

索引数据结构:二叉树、红黑树、hash表、B-tree

1、普通索引当一张表,把某个列设为主键的时候,则该列就是主键索引

2、唯一索引索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

3、主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。

4、组合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合。

5、全文索引主要用来查找文本中的关键字,而不是直接与索引中的值相比较。

InnoDB索引实现(聚集)

  • 数据文件本身就是索引文件
  • 表数据文件本身就是按B+树组织的一个索引结构文件
  • 聚集索引的叶子节点包含了完整的数据记录
  • 表必须有主键,且推荐使用整型的自增主键
  • 普通索引结构叶子节点存储的是主键值

InnoDB主键索引查找流程:通过.ibd文件找到对应的索引,索引的value即为那行对应的完整数据

聚集索引和非聚集索引的区别?

聚集索引:表中那行数据的索引和数据都合并在一起了。

非聚集索引:表中那行数据的索引和数据是分开存储的。

一个 SQL 执行的很慢,我们要分两种情况讨论:

1、偶尔很慢,则有如下原因

(1)、数据库在刷新脏页,例如 redo log 写满了需要同步到磁盘。

(2)、执行的时候,遇到锁,如表锁、行锁。

2、这条 SQL 语句一直执行的很慢,则有如下原因。

(1)、没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引。

(2)、数据库选错了索引。

Redis

redis常见的数据结构以及应用场景:

String:key -value缓存应用,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。

Hash:field-value映射表,存储用户信息和商品信息

List:list分页查询

Set:实现差,并,交集操作,比如共同喜好等

Sorted set:用户列表,礼物排行榜,弹幕消息

缓存雪崩

缓存同一时间大面积失效,所有请求都落到数据库造成短时间内承受大量请求而崩掉

如何解决缓存雪崩?在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。

对于“Redis挂掉了,请求全部走数据库”这种情况,我们可以有以下的思路:

事发前:实现Redis的高可用(主从架构+Sentinel 或者Redis Cluster),尽量避免Redis挂掉这种情况发生。

事发中:设置本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库***掉(起码能保证我们的服务还是能正常工作的)

事发后:redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。

缓存穿透

恶意请求缓存中不存在的数据,所有求情都落到数据库造成短时间内承受大量请求而崩掉

如何解决缓存穿透?

(一)利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试

(二)采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。

(三)提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。

Redis和数据库双写一致性?

首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。

采用延时双删策略

(1)先淘汰缓存
(2)再写数据库(这两步和原来一样)
(3)休眠1秒,再次淘汰缓存

Redis的内存淘汰机制:Redis提供了8种内存淘汰策略

  1. volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
  5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。
  7. volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
  8. allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key

如何解决 Redis 的并发竞争 Key 问题
所谓 Redis 的并发竞争 Key 的问题也就是多个系统同时对一个 key 进行操作,最后执行的顺序和我们期望的顺序不同,导致了结果的不同!推荐一种方案:分布式锁(zookeeper 和 redis 都可以实现分布式锁)。

基于zookeeper临时有序节点可以实现的分布式锁。大致思想为:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。 当释放锁的时候,只需将这个瞬时节点删除即可。

redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)

1、快照(snapshotting)持久化(RDB)

Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。快照持久化是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置
2、AOF(append-only file)持久化

与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF方式的持久化,可以通过appendonly参数开启.Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

● 请问,为什么 redis 读写速率快、性能好?

Redis是纯内存数据库,相对于读写磁盘,读写内存的速度就不是几倍几十倍了,一般hash查找可以达到每秒百万次的数量级。

多路复用IO,“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗)。可以直接理解为:单线程的原子操作,避免上下文切换的时间和性能消耗;加上对内存中数据的处理速度,很自然的提高redis的吞吐量。

3、SSM

1、spring

● 请问什么是IoC和DI?并且简要说明一下DI是如何实现的?

IoC叫控制反转,DI叫依赖注入。控制反转是把传统上由程序代码直接操控的对象的调用权交给容器通过容器来实现对象组件的装配和管理。"控制反转"就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。DI是对IoC更准确的描述,即组件之间的依赖关系由容器在运行期决定,即由容器动态的将某种依赖关系注入到组件之中。
依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。

依赖注入是从应用程序的角度在描述:应用程序依赖容器创建并注入它所需要的外部资源;

控制反转是从容器的角度在描述:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

● 请说明一下springIOC原理是什么?如果你要实现IOC需要怎么做?请简单描述一下实现步骤

①IoC这是spring的核心,由spring来负责控制对象的生命周期和对象间的关系

IoC的一个在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI来实现的。比如对象A需要操作数据库,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像***一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

②实现IOC的步骤

定义用来描述bean的配置的Java类、解析bean的配置、遍历存放HashMap对象

● 请谈一谈Spring中自动装配的方式有哪些?

  • no:不进行自动装配,手动设置Bean的依赖关系。
  • byName:根据Bean的名字进行自动装配。
  • byType:根据B

你可能感兴趣的:(java)