《面试填坑系列》大厂常问Java高级面试100题解析(一)

Java高级面试100题及解析

数据库篇

  1. 事务四大特性(ACID)原子性、一致性、隔离性、持久性?
  2. 事务的并发?事务隔离级别,每一个级别会引起什么问题,MySQL默认是哪一个级别?
  3. MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?
  4. MySQL的MyISAM与InnoDB两种存储引擎在,事务、锁级别,各自的适用场景?
  5. MySQL B+Tree 索引和 Hash 索引的区别?
  6. sql 查询语句肯定建立哪一种类型的索引,如何优化查询
  7. 有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?
  8. 数据库的读写分离、主从复制,主从复制分析的 7 个问题?
  9. MySQL 都有什么锁,死锁断定原理和具体场景,死锁怎么解决?
  10. MySQL 高并发环境解决方案?

Spring篇

  1. Spring IoC、AOP 原理
  2. Spring Bean 生命周期 
  3. Spring Bean 注入是如何解决循环依赖问题的
  4. 怎样用注解的方式配置 Spring?
  5. Spring 事务为什么失效了
  6. SpringMVC 的流程?
  7. Springmvc 的优势:
  8. Spring 通知类型使用场景分别有哪些?
  9. IoC 控制反转设计原理?
  10. Spring 如何处理线程并发问题?

JVM篇

  1. Java 类加载过程?
  2. 描述一下 JVM 加载 Class 文件的原理机制?
  3. 简述 Java 垃圾回收机制。
  4. 什么是类加载器,类加载器有哪些?
  5. 如何判断一个对象是否存活?(或者 GC 对象的断定方法)
  6. 垃圾回收的优势和原理。并考虑 2 种回收机制。
  7. 垃圾回收器的基本原理是什么?垃圾回收器能够立刻回收内存吗?有什么办法主动通知虚拟机进行垃圾回收
  8. Java 中会存在内存泄漏吗,请简单描述。
  9. 简述 Java 内存分配与回收策率以及 Minor GC 和 Major GC。
  10. Java 中垃圾收集的方法有哪些?

Java并发篇

  1. Synchronized 用过吗,其原理是什么?
  2. 为何说 Synchronized 是非公平锁?
  3. 为何说 Synchronized 是一个悲观锁?乐观锁的实现原理又是什么?什么是 CAS,它有
  4. 请尽量详尽地对比下 Synchronized 和 ReentrantLock 的异同。
  5. 谈谈 ReadWriteLock 和 StampedLock。
  6. 如何让 Java 的线程彼此同步?你了解过哪些同步器?请分别介绍下。
  7. 线程池中的线程是怎么建立的?是一开始就随着线程池的启动建立好的吗?
  8. 提到能够经过配置不一样参数建立出不一样的线程池,那么 Java 中默认实现好的线程池又有哪些呢?请比
  9. 如何在 Java 线程池中提交线程?
  10. 请谈谈 volatile 有什么特色,为何它能保证变量对全部线程的可见性?

Redis缓存篇

  1. 什么是 Redis 事务?原理是什么?
  2. 请介绍一下 Redis 的数据类型 SortedSet(zset)以及底层实现机制?
  3. Redis 经常使用的命令有哪些?
  4. 什么是缓存穿透?怎么解决?
  5. 什么是缓存雪崩? 怎么解决?
  6. 请介绍几个可能致使 Redis 阻塞的缘由
  7. 缓存的更新策略有几种?分别有什么注意事项?
  8. Redis 为何设计成单线程的?
  9. Redis 持久化机制 AOF 和 RDB 有哪些不一样之处?
  10. Redis 缓存失效策略有哪些?

RabbitMQ篇

  1. RabbitMQ 的使用场景有哪些?
  2. RabbitMQ 有哪些重要的角色?
  3. RabbitMQ 有哪些重要的组件?
  4. RabbitMQ 的消息是怎么发送的?
  5. RabbitMQ 怎么保证消息的稳定性?
  6. RabbitMQ 怎么避免消息丢失?
  7. 要保证消息持久化成功的条件有哪些?
  8. RabbitMQ 有几种广播类型?
  9. RabbitMQ 怎么实现延迟消息队列?
  10. RabbitMQ 集群中惟一一个磁盘节点崩溃了会发生什么状况?

Java集合篇

  1. ArrayList 和 Vector 的区别
  2. 说说 ArrayList,Vector, LinkedList 的存储性能和特性
  3. 快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么?
  4. hashmap 的数据结构。
  5. HashMap 的工做原理是什么?
  6. Hashmap 何时进行扩容呢?
  7. HashSet 和 TreeSet 有什么区别?
  8. HashSet 的底层实现是什么?
  9. LinkedHashMap 的实现原理?
  10. Collection 和 Collections 的区别。

微服务篇

  1. 使用Spring Cloud有什么优点?
  2. 服务注册和发现是什么意思?Spring Cloud如何实现?
  3. 负载平衡的意义什么?
  4. 什么是Hystrix?它如何实现容错?
  5. 什么是Hystrix断路器?咱们须要它吗?
  6. 什么是Netflix Feign?它的优势是什么?
  7. Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
  8. Spring Boot 的核心注解是哪一个?它主要由哪几个注解组成的?
  9. Spring Boot中的监视器是什么?
  10. 什么是Swagger?你用Spring Boot实现了它吗?

Zookeeper篇

  1. zk的命名服务(文件系统)
  2. zk的配置管理(文件系统、通知机制)
  3. Zookeeper集群管理(文件系统、通知机制)
  4. Zookeeper分布式锁(文件系统、通知机制)
  5. 获取分布式锁的流程
  6. Zookeeper队列管理(文件系统、通知机制)
  7. Zookeeper数据复制
  8. Zookeeper工做原理
  9. zookeeper是如何保证事务的顺序一致性的?
  10. Zookeeper 下 Server工做状态

解决方案篇

本次更新Java 面试题(一)的1~20题答案

数据库篇

1. 事务四大特性(ACID)原子性、一致性、隔离性、持久性?

1.1. 原子性(Atomicity)前端

原子性是指事务包含的全部操做要么所有成功,要么所有失败回滚,所以事务的操做若是成功就必需要彻底应用到数据库,若是操做失败则不能对数据库有任何影响。

1.2. 一致性(Consistency)java

事务开始前和结束后,数据库的完整性约束没有被破坏。好比 A B 转帐,不可能 A 扣了钱, B 却没收到

1.3. 隔离性(Isolation)面试

隔离性是当多个用户并发访问数据库时,好比操做同一张表时,数据库为每个用户开启的事务, 不能被其余事务的操做所干扰,多个并发事务之间要相互隔离

同一时间,只容许一个事务请求同一数据,不一样的事务之间彼此没有任何干扰。好比A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转帐。

1.4.持久性(Durability)

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即使是在数据库系统遇到故障的状况下也不会丢失提交事务的操做

2.事务的并发?事务隔离级别,每一个级别会引起什么问题,MySQL默认是哪一个级别?

从理论上来讲,事务应该彼此彻底隔离,以免并发事务所致使的问题,然而,那样会对性能产生极大的影响,由于事务必须按顺序运行, 在实际开发中 , 为了提高性能 , 事务会以较低的隔离级别运行, 事务的隔离级别能够经过隔离事务属性指定

2.1事务的并发问题算法

一、脏读:事务A读取了事务B更新的数据,而后B回滚操做,那么A读取到的数据是脏数据sql

二、不可重复读:事务A屡次读取同一数据,事务B在事务A屡次读取的过程当中,对数据做了更新并提交,致使事务A屡次读取同一数据时,结果所以本事务前后两次读到的数据结果会不一致。数据库

三、幻读:幻读解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。编程

例如:事务T1对一个表中全部的行的某个数据项作了从“1”修改成“2”的操做这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值仍是为“1”而且提交给数据库。而操做事务T1的用户若是再查看刚刚修改的数据,会发现还有跟没有修改同样,其实这行是从事务T2中添加的,就好像产生幻觉同样,这就是发生了幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住知足条件的行,解决幻读须要锁表。

2.2事务的隔离级别后端

事务隔离级别缓存

脏读安全

不可重复读

幻读

读未提交 read-uncommitted

不可重复读 read-committed

可重复读 repeatable-read

串行化 serializable

读未提交:另外一个事务修改了数据,但还没有提交,而本事务中的SELECT会读到这些未被提交的数据 脏读

不可重复读:事务A屡次读取同一数据,事务B在事务A屡次读取的过程当中,对数据做了更新并提交,致使事务A屡次读取同一数据时,结果所以本事务前后两次读到的数据结果会不一致。

可重复读:在同一个事务里,SELECT的结果是事务开始时时间点的状态,所以,一样的
SELECT 操做读到的结果会是一致的。可是,会有 幻读现象

串行化:最高的隔离级别,在这个隔离级别下,不会产生任何异常。并发的事务,就像事务是在一个个按照顺序执行同样

MySQL默认的事务隔离级别为repeatable-read 

MySQL支持4中事务隔离级别

事务的隔离级别要获得底层数据库引擎的支持,而不是应用程序或者框架的支持. 

Oracle支持的2种事务隔离级别:READ_COMMITED , SERIALIZABLE

2.3补充

1. SQL规范所规定的标准,不一样的数据库具体的实现可能会有些差别

2. MySQL中默认事务隔离级别是“可重复读”时并不会锁住读取到的行

  • 事务隔离级别未提交读时,写数据只会锁住相应的行。
  • 事务隔离级别为可重复读时,写数据会锁住整张表。
  • 事务隔离级别为串行化时,读写数据都会锁住整张表。

隔离级别越高越能保证数据的完整性和一致性,可是对并发性能的影响也越大,鱼和熊掌不可兼得啊。 对于多数应用程序,能够优先考虑把数据库系统的隔离级别设为 Read Committed
,它可以避免脏读取,并且具备较好的并发性能。尽管它会致使不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,能够由应用程序采用悲观锁或乐观锁来控制。

3. MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别?

MySQL 存储引擎 MyISAM 与 InnoDB 如何选择

MySQL 有多种存储引擎,每种存储引擎有各自的优缺点,能够择优选择使用:MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE

虽然 MySQL 里的存储引擎不仅是 MyISAM 与 InnoDB 这两个,但经常使用的就是两个

两种存储引擎的大体区别表如今

  • InnoDB 支持事务,MyISAM 不支持,这一点是很是之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪一个出错还能够回滚还原,而 MyISAM 就不能够了。
  • MyISAM 适合查询以及插入为主的应用
  • InnoDB 适合频繁修改以及涉及到安全性较高的应用
  • InnoDB 支持外键,MyISAM 不支持。
  • 从 MySQL5.5.5 之后,InnoDB 是默认引擎
  • InnoDB 不支持 FULLTEXT 类型的索引。
  • InnoDB 中不保存表的行数,如select count(*) from table时,InnoDB 须要扫描一遍整个表来计算有多少行,可是 MyISAM 只要简单的读出保存好的行数便可。注意的是,当 count(*)语句包含 where 条件时 MyISAM 也须要扫描整个表。
  • 对于自增加的字段,InnoDB 中必须包含只有该字段的索引,可是在 MyISAM 表中能够和其余字段一块儿创建联合索引。
  • DELETE FROM table时,InnoDB 不会从新创建表,而是一行一行的 删除,效率很是慢MyISAM 则会重建表
  • InnoDB 支持行锁(某些状况下仍是锁整表,如 update table set a=1 where user like '%lee%'

关于 MySQL 数据库提供的两种存储引擎,MyISAM 与 InnoDB 选择使用:

  • INNODB 会支持一些关系数据库的高级功能如事务功能和行级锁,MyISAM 不支持
  • MyISAM 的性能更优,占用的存储空间少,因此,选择何种存储引擎,视具体应用而定。
  • 若是你的应用程序必定要使用事务,毫无疑问你要选择 INNODB 引擎。但要注意,INNODB 的行级锁是有条件的。在 where 条件没有使用主键时,照样会锁全表。好比 DELETE FROM mytable 这样的删除语句。
  • 若是你的应用程序对查询性能要求较高,就要使用 MyISAM 了MyISAM 索引和数据是分开的,并且其索引是压缩的,能够更好地利用内存。因此它的查询性能明显优于 INNODB。压缩后的索引也能节约一些磁盘空间。MyISAM 拥有全文索引的功能,这能够极大地优化 LIKE 查询的效率

有人说 MyISAM 只能用于小型应用,其实这只是一种偏见。若是数据量比较大,这是须要经过升级架构来解决,好比分表分库,而不是单纯地依赖存储引擎。

如今通常都是选用 innodb 了,主要是 MyISAM 的全表锁,读写串行问题,并发效率锁表,效率低,MyISAM 对于读写密集型应用通常是不会去选用的。

4. MySQL的MyISAMInnoDB两种存储引擎在,事务、锁级别,各自的适用场景?

事务处理上方面

  • MyISAM强调的是性能,每次查询具备原子性,其执行数度比 InnoDB 类型更快,可是不提供事务支持
  • InnoDB提供事务支持事务,外部键等高级数据库功能。 具备事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。

锁级别

  • MyISAM只支持表级锁,用户在操做 MyISAM 表时,select,update,delete,insert 语句都会给表自动加锁,若是加锁之后的表知足 insert 并发的状况下,能够在表的尾部插入新的数据。
  • InnoDB:支持事务和行级锁,是 innodb 的最大特点。行锁大幅度提升了多用户并发操做的新能。可是 InnoDB 的行锁,只是在 WHERE 的主键是有效的,非主键的 WHERE 都会锁全表的。

5.MySQL B+Tree 索引和 Hash 索引的区别?

  • Hash 索引结构的特殊性,其检索效率很是高,索引的检索能够一次定位;
  • B+树索引须要从根节点到枝节点,最后才能访问到页节点这样屡次的 IO 访问;

那为何你们不都用 Hash 索引而还要使用 B+树索引呢?

Hash 索引

  1. Hash 索引仅仅能知足"=","IN"和"<=>"查询,不能使用范围查询,由于通过相应的 Hash 算法处理以后的 Hash 值的大小关系,并不能保证和 Hash 运算前彻底同样;
  2. Hash 索引没法被用来避免数据的排序操做,由于 Hash 值的大小关系并不必定和 Hash 运算前的键值彻底同样;
  3. Hash 索引不能利用部分索引键查询,对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再一块儿计算 Hash 值,而不是单独计算 Hash 值,因此经过组合索引的前面一个或几个索引键进行查询的时候,Hash 索引也没法被利用;
  4. Hash 索引在任什么时候候都不能避免表扫描,因为不一样索引键存在相同 Hash 值,因此即便取知足某个 Hash 键值的数据的记录条数,也没法从 Hash 索引中直接完成查询,仍是要回表查询数据;
  5. Hash 索引遇到大量 Hash 值相等的状况后性能并不必定就会比 B+树索引高。

B+Tree 索引

MySQL 中,只有 HEAP/MEMORY 引擎才显示支持 Hash 索引

经常使用的 InnoDB 引擎中默认使用的是 B+树索引,它会实时监控表上索引的使用状况,若是认为创建哈希索引能够提升查询效率,则自动在内存中的“自适应哈希索引缓冲区”创建哈希索引(在 InnoDB 中默认开启自适应哈希索引),经过观察搜索模式,MySQL 会利用 index key 的前缀创建哈希索引,若是一个表几乎大部分都在缓冲池中,那么创建一个哈希索引可以加快等值查询。

B+树索引和哈希索引的明显区别是:

若是是等值查询,那么哈希索引明显有绝对优点由于只须要通过一次算法便可找到相应的键值;固然了,这个前提是,键值都是惟一的。若是键值不是惟一的,就须要先找到该键所在位置,而后再根据链表日后扫描,直到找到相应的数据

若是是范围查询检索,这时候哈希索引就毫无用武之地了,由于原先是有序的键值,通过哈希算法后,有可能变成不连续的了,就没办法再利用索引完成范围查询检索;

同理,哈希索引没办法利用索引完成排序,以及 like ‘xxx%’ 这样的部分模糊查询(这种部分模糊查询,其实本质上也是范围查询);

哈希索引也不支持多列联合索引的最左匹配规则

B+树索引的关键字检索效率比较平均,不像 B 树那样波动幅度大,在有大量重复键值状况下,哈希索引的效率也是极低的,由于存在所谓的哈希碰撞问题

在大多数场景下,都会有范围查询、排序、分组等查询特征,用 B+树索引就能够了

6.sql 查询语句肯定建立哪一种类型的索引,如何优化查询

  • 性能优化过程当中,选择在哪一个列上建立索引是最重要的步骤之一,能够考虑使用索引的主要有两种类型的列:在 where 子句中出现的列,在 join 子句中出现的列。
  • 考虑列中值的分布,索引的列的基数越大,索引的效果越好。
  • 使用短索引,若是对字符串列进行索引,应该指定一个前缀长度,可节省大量索引空间,提高查询速度。
  • 利用最左前缀,顾名思义,就是最左优先,在多列索引,有体现:(ALTER TABLE people ADD INDEX lname
    fname
    age (lame,fname,age);),所谓最左前缀原则就是先要看第一列,在第一列知足的条件下再看左边第二列,以此类推
  • 不要过分建索引,只保持所需的索引。每一个额外的索引都要占用额外的磁盘空间,并下降写操做的性能
  • 在修改表的内容时,索引必须进行更新,有时可能须要重构,所以,索引越多,所花的时间越长
  • MySQL 只对一下操做符才使用索引<,<=,=,>,>=,between,in
  • 以及某些时候的 like(不以通配符%或_开头的情形)。

7.有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?

悲观锁(Pessimistic Lock)

悲观锁的特色是先获取锁,再进行业务操做,即“悲观”的认为获取锁是很是有可能失败的,所以要先确保获取锁成功再进行业务操做。一般所说的“一锁二查三更新”即指的是使用悲观锁。一般来说在数据库上的悲观锁须要数据库自己提供支持,即经过经常使用的 select … for update 操做来实现悲观锁。当数据库执行 select for update 时会获取被 select 中的数据行的行锁,所以其余并发执行的 select for update 若是试图选中同一行则会发生排斥(须要等待行锁被释放),所以达到锁的效果。select for update 获取的行锁会在当前事务结束时自动释放,所以必须在事务中使用。

这里须要注意的一点是不一样的数据库对 select for update 的实现和支持都是有所区别的,例如 oracle 支持 select for update no wait,表示若是拿不到锁马上报错,而不是等待,MySQL 就没有 no wait 这个选项。另外MySQL 还有个问题是 select for update 语句执行中全部扫描过的行都会被锁上,这一点很容易形成问题。所以若是在 MySQL 中用悲观锁务必要肯定走了索引,而不是全表扫描

乐观锁(Optimistic Lock)

乐观锁,也叫乐观并发控制,它假设多用户并发的事务在处理时不会彼此互相影响,各事务可以在不产生锁的状况下处理各自影响的那部分数据。在提交数据更新以前,每一个事务会先检查在该事务读取数据后,有没有其余事务又修改了该数据。若是其余事务有更新的话,那么当前正在提交的事务会进行回滚

乐观锁的特色先进行业务操做,不到万不得已不去拿锁。即“乐观”的认为拿锁多半是会成功的,所以在进行完业务操做须要实际更新数据的最后一步再去拿一下锁就好。

乐观锁在数据库上的实现彻底是逻辑的,不须要数据库提供特殊的支持通常的作法是在须要锁的数据上增长一个版本号,或者时间戳,而后按照以下方式实现:

乐观锁(给表加一个版本号字段) 这个并非乐观锁的定义,给表加版本号,是数据库实现乐观锁的一种方式

1\. SELECT data AS old_data, version AS old_version FROM …;
2\. 根据获取的数据进行业务操做,获得 new_data 和 new_version
3\. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
    // 乐观锁获取成功,操做完成
} else {
    // 乐观锁获取失败,回滚并重试
}
复制代码

乐观锁在不发生取锁失败的状况下开销比悲观锁小,可是一旦发生失败回滚开销则比较大,所以适合用在取锁失败几率比较小的场景,能够提高系统并发性能

乐观锁还适用于一些比较特殊的场景,例如在业务操做过程当中没法和数据库保持链接等悲观锁没法适用的地方

总结

悲观锁和乐观锁是数据库用来保证数据并发安全防止更新丢失的两种方法,例子在select ... for update前加个事务就能够防止更新丢失。悲观锁和乐观锁大部分场景下差别不大,一些独特场景下有一些差异,通常咱们能够从以下几个方面来判断。

  • 响应速度:若是须要很是高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不须要等待其余并发去释放锁。

  • 冲突频率:若是冲突频率很是高,建议采用悲观锁,保证成功率,若是冲突频率大,乐观锁会须要屡次重试才能成功,代价比较大。

  • 重试代价:若是重试代价大,建议采用悲观锁。

8.数据库的读写分离、主从复制,主从复制分析的 7 个问题?

主从复制的几种方式

同步复制

  • 所谓的同步复制,意思是 master 的变化,必须等待 slave-1,slave-2,...,slave-n 完成后才能返回。 这样,显然不可取,也不是 MySQL 复制的默认设置。好比,在 WEB 前端页面上,用户增长了条记录,须要等待很长时间。

异步复制

  • 如同 AJAX 请求同样。master 只须要完成本身的数据库操做便可。至于 slaves 是否收到二进制日志,是否完成操做,不用关心,MySQL 的默认设置。

半同步复制

  • master 只保证 slaves 中的一个操做成功,就返回,其余 slave 无论。 这个功能,是由 google 为 MySQL 引入的。

主从复制分析的 7 个问题

问题 1:master 的写操做,slaves 被动的进行同样的操做,保持数据一致性,那么 slave 是否能够主动的进行写操做?

假设 slave 能够主动的进行写操做,slave 又没法通知 master,这样就致使了 master 和 slave 数据不一致了。所以slave 不该该进行写操做,至少是 slave 上涉及到复制的数据库不能够写。实际上,这里已经揭示了读写分离的概念

问题 2:主从复制中,能够有 N 个 slave,但是这些 slave 又不能进行写操做,要他们干吗?

以实现数据备份

相似于高可用的功能,一旦 master 挂了,可让 slave 顶上去,同时 slave 提高为 master

异地容灾,好比 master 在北京,地震挂了,那么在上海的 slave 还能够继续。

主要用于实现 scale out,分担负载,能够将读的任务分散到 slaves 上

极可能的状况是,一个系统的读操做远远多于写操做,所以写操做发向 master,读操做发向 slaves 进行操做

问题 3:主从复制中有 master,slave1,slave2,...等等这么多 MySQL 数据库,那好比一个 JAVA WEB 应用到底应该链接哪一个数据库?

当 然,咱们在应用程序中能够这样,insert/delete/update这些更新数据库的操做,用connection(for master)进行操做,select 用 connection(for slaves)进行操做。那咱们的应用程序还要完成怎么从 slaves 选择一个来执行 select,例如使用简单的轮循算法

这样的话,至关于应用程序完成了 SQL 语句的路由,并且与 MySQL 的主从复制架构很是关联,一旦 master 挂了,某些 slave 挂了,那么应用程序就要修改了。能不能让应用程序与 MySQL 的主从复制架构没有什么太多关系呢?

找一个组件application program 只须要与它打交道,用它来完成 MySQL 的代理,实现 SQL 语句的路由

MySQL proxy 并不负责,怎么从众多的 slaves 挑一个?能够交给另外一个组件(好比 haproxy)来完成。

这就是所谓的MySQL READ WRITE SPLITE,MySQL的读写分离。

问题 4:若是 MySQL proxy , direct , master 他们中的某些挂了怎么办?

总统通常都会弄个副总统,以防不测。一样的,能够给这些关键的节点来个备份。

问题 5:当 master 的二进制日志每产生一个事件,都须要发往 slave,若是咱们有 N 个 slave,那是发 N 次,仍是只发一次?

若是只发一次,发给了 slave-1,那 slave-2,slave-3,...它们怎么办?

显 然,应该发 N 次。实际上,在 MySQL master 内部,维护 N 个线程,每个线程负责将二进制日志文件发往对应的 slave。master 既要负责写操做,还的维护 N 个线程,负担会很重。能够这样,slave-1 是 master 的从,slave-1 又是 slave-2,slave-3,...的主,同时 slave-1 再也不负责 select。 slave-1 将 master 的复制线程的负担,转移到本身的身上这就是所谓的多级复制的概念

问题 6:当一个 select 发往 MySQL proxy,可能此次由 slave-2 响应,下次由 slave-3 响应,这样的话,就没法利用查询缓存了。

应该找一个共享式的缓存,好比 memcache 来解决。将 slave-2,slave-3,...这些查询的结果都缓存至 mamcache 中。

问题 7:随着应用的日益增加,读操做不少,咱们能够扩展 slave,可是若是 master 知足不了写操做了,怎么办呢?

scale on ?更好的服务器? 没有最好的,只有更好的,太贵了。。。

scale out ? 主从复制架构已经知足不了。

能够分库【垂直拆分】,分表【水平拆分】。

9.MySQL 都有什么锁,死锁断定原理和具体场景,死锁怎么解决?

MySQL 都有什么锁

MySQL 有三种锁的级别:页级、表级、行级

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的几率最高,并发度最低。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。
  • 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常

什么状况下会形成死锁

  • 所谓死锁: 是指两个或两个以上的进程在执行过程当中。
  • 因争夺资源而形成的一种互相等待的现象,若无外力做用,它们都将没法推动下去。
  • 此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程。
  • 表级锁不会产生死锁.因此解决死锁主要仍是针对于最经常使用的 InnoDB。

死锁的关键在于:两个(或以上)的 Session 加锁的顺序不一致。

那么对应的解决死锁问题的关键就是:让不一样的 session加锁有次序

死锁的解决办法

  • 查出的线程杀死 kill
SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX;
复制代码
  • 设置锁的超时时间

Innodb 行锁的等待时间,单位秒。可在会话级别设置,RDS 实例该参数的默认值为 50(秒)。

生产环境不推荐使用过大的 innodb_lock_wait_timeout参数值

该参数支持在会话级别修改,方便应用在会话级别单独设置某些特殊操做的行锁等待超时时间,以下:

set innodb_lock_wait_timeout=1000; —设置当前会话 Innodb 行锁等待超时时间,单位秒。复制代码

10.MySQL 高并发环境解决方案?

MySQL 高并发环境解决方案 分库 分表 分布式 增长二级缓存。。。。。

需求分析:互联网单位 天天大量数据读取,写入,并发性高。

  • 现有解决方式:水平分库分表,由单点分布到多点数据库中,从而下降单点数据库压力。
  • 集群方案:解决 DB 宕机带来的单点 DB 不能访问问题。
  • 读写分离策略:极大限度提升了应用中 Read 数据的速度和并发量。没法解决高写入压力。

Spring全家桶

1.Spring IoC、AOP 原理

1.1.定义

1.1.1.IoC

Inversion of Control,控制反转。是面向对象编程中的一种设计原则,能够用来减低计算机代码之间的耦合度。其中最多见的方式叫作依赖注入(DependencyInjection,简称 DI),这也是 Spring 的实现方式。经过控制反转,对象在被建立的时候,由一个调控系统内全部对象的外界实体将其所依赖的对象的引用传递给它。也能够说,依赖被注入到对象中。 

1.1.2.AOP

Aspect Oriented Programming,面向切面编程。经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,是软件开发中的一个热点,也是 Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 能够对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度下降,提升程序的可重用性,同时提升了开发的效率。其中,最经常使用的使用场景通常有日志模块、权限模块、事物模块。

1.2.原理

1.2.1.IoC

IoC 内部核心原理就是反射技术,固然这里面还涉及到 Bean 对象的初始化构建等步骤,这个在后面的生命周期中讲,这里咱们须要了解 Java 中反射是如何作的就好。这里主要说明下主要的相关类和可能面试问题转向,具体的 API 实现须要本身去看。 

还有其余的类不一一列举出来,都在 java.lang.reflect 包下。说到这个模块的时候,那么面试官可能会考察相关的知识,主要是考察你是否真的有去了解过反射的使用。举两个例子: 

利用反射获取实例的私有属性值怎么作

这里其实就是里面的重要考察点就是反射对私有属性的处理。

/**
 * 经过反射获取私有的成员变量.
 */
private Object getPrivateValue(Person person, String fieldName)
{
    try
    {
        Field field = person.getClass().getDeclaredField(fieldName);
        // 主要就是这里,须要将属性的 accessible 设置为 true 
        field.setAccessible(true);
        return field.get(person);
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    return null;
}复制代码

如何经过反射构建对象实例?

使用默认构造函数(无参)建立的话: 

Class.newInstance() Constroctor constroctor = clazz.getConstructor(String.class,Integer.class); Object obj = constroctor.newInstance("name", 18);
复制代码

1.2.2.AOP

AOP 的内部原理其实就是动态代理和反射了。主要涉及到的反射类: 


动态代理相关原理的话,你须要了解什么是代理模式、静态代理的不足、动态代理的实现原理。 Spring 中实现动态代理有两种方式可选,这两种动态代理的实现方式的一个对比也
是面试中常问的。 

JDK 动态代理 

必须实现 InvocationHandler 接口,而后经过 Proxy.newProxyInstance(ClassLoader
loader, Class<?>[] interfaces, InvocationHandler h) 得到动态代理对象。
CGLIB 动态代理

使用 CGLIB 动态代理,被代理类不须要强制实现接口。CGLIB 不能对声明为 final的方法进行代理,由于 CGLIB 原理是动态生成被代理类的子类。

OK,AOP 讲了。其实讲到这里,可能会有一个延伸的面试问题。咱们知道,Spring事物也是 通 过 AOP 来 实 现的 , 咱们使用的时候 一 般就是在方法上 加@Tranactional 注解,那么你有没有遇到过事物不生效的状况呢?这是为何?这个问题咱们在后面的面试题中会讲。 

2.Spring Bean 生命周期 


这只是个大致流程,内部的具体行为太多,须要自行去看看代码。 

3.Spring Bean 注入是如何解决循环依赖问题的 

3.1. 什么是循环依赖,有啥问题? 

循环依赖就是 N 个类中循环嵌套引用,这样会致使内存溢出。循环依赖主要分两种:

  • 构造器循环依赖
  • setter 循环依赖
3.2. Spring 解决循环依赖问题 
  • 构造器循环依赖问题 
无解,直接抛出 BeanCurrentlyInCreatingException 异常。
  • setter 循环依赖问题 
单例模式下,经过“三级缓存”来处理。非单例模式的话,问题无解。 

Spring 初始化单例对象大致是分为以下三个步骤的:

  • createBeanInstance:调用构造函数建立对象
  • populateBean:调用类的 setter 方法填充对象属性
  • initializeBean:调用定义的 Bean 初始化 init 方法
能够看出,循环依赖主要发生在 一、2 步,固然若是发生在第一步的话,Spring 也是没法解决该问题的。那么就剩下第二步 populateBean 中出现的循环依赖问题。经过“三级缓存”来处理,三级缓存以下:

  • singletonObjects:Cache of singleton objects: bean name --> bean instance,完成初始化的单例对象的 cache(一级缓存)
  • earlySingletonObjects:Cache of early singleton objects: bean name--> bean instance ,完成实例化可是还没有初始化的,提早暴光的单例对象的 cache (二级缓存)
  • singletonFactories : Cache of singleton factories: bean name -->ObjectFactory,进入实例化阶段的单例对象工厂的 cache (三级缓存) 

咱们看下获取单例对象的方法:

protected Object getSingleton(String beanName, boolean allowEarlyReference)
{
    Object singletonObject = this.singletonObjects.get(beanName);
    // isSingletonCurrentlyInCreation:判断当前单例 bean 是否正在建立中 
    if(singletonObject == null && isSingletonCurrentlyInCreation(beanName))
    {
        synchronized(this.singletonObjects)
        {
            singletonObject = this.earlySingletonObjects.get(beanName);
            // allowEarlyReference:是否容许从 singletonFactories 中经过 getObject 拿到 
            对象
            if(singletonObject == null && allowEarlyReference)
            {
                ObjectFactory <? > singletonFactory = this.singletonFactories.get(beanName);
                if(singletonFactory != null)
                {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return(singletonObject != NULL_OBJECT ? singletonObject : null);
}
复制代码

其中解决循环依赖问题的关键点就在 singletonFactory.getObject() 这一步,getObject 这是 ObjectFactory<T> 接口的方法。Spring 经过对该方法的实现,在createBeanInstance 以后,populateBean 以前,经过将建立好但还没完成属性设置和初始化的对象提早曝光,而后再获取 Bean 的时候去看是否有提早曝光的对象实例来判断是否要走建立流程。

protected void addSingletonFactory(String beanName, ObjectFactory <? > singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized(this.singletonObjects)
    {
        if(!this.singletonObjects.containsKey(beanName))
        {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}复制代码

4.Spring 事务为什么失效了

可能的缘由:

  1. MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事务的。须要支持使用可使用 InnoDB 引擎
  2. 若是使用了 Spring MVC ,context:component-scan 重复扫描问题可能会引发事务失败
  3. @Transactional 注解开启配置放到 DispatcherServlet 的配置里了。
  4. @Transactional 注解只能应用到 public 可见度的方法上。 在其余可见类型上声明,事务会失效。
  5. 在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因此若是强制使用了 CGLIB,那么事物会实效。
  6. @Transactional 同一个类中无事务方法 a() 内部调用有事务方法 b(),那么此时事物不生效。 
按 理 说 , 如 果 按 照 Spring 说 的 事 物 传 播 级 别 去 配 置 其 事 物 级 别 为REQUIRES_NEW 的话,那么应该是在调用 b() 的时候会新生成一个事物。实际上却没有。



NOT_SUPPORTED 老是非事务地执行,并挂起任何存在的事务其实,这是因为 Spring 的事物实现是经过 AOP 来实现的。此时,当这个有注解的方法 b() 被调用的时候,其实是由代理类来调用的,代理类在调用以前就会启动 transaction。然而,若是这个有注解的方法是被同一个类中的其余方法 a() 调用的,那么该方法的调用并无经过代理类,而是直接经过原来的那个 bean,因此就不会启动 transaction,咱们看到的现象就是 @Transactional 注解无效。 

5.怎样用注解的方式配置 Spring?

Spring 在 2.5 版本之后开始支持用注解的方式来配置依赖注入。能够用注解的方式来替代XML 方式的 bean 描述,能够将 bean 描述转移到组件类的内部,只须要在相关类上、方法上或者字段声明上使用注解便可。注解注入将会被容器在 XML 注入以前被处理,因此后者会覆盖掉前者对于同一个属性的处理结果。注解装配在 Spring 中是默认关闭的。因此须要在 Spring 文件中配置一下才能使用基于注解的装配模式。若是你想要在你的应用程序中使用关于注解的方法的话,请参考以下的配置。 

<beans>
    <context:annotation-config/>
    <!-- bean definitions go here -->
</beans>复制代码

在标签配置完成之后,就能够用注解的方式在 Spring 中向属性、方法和构造方法中自动装配变量。

下面是几种比较重要的注解类型:

  • @Required:该注解应用于设值方法。
  • @Autowired:该注解应用于有值设值方法、非设值方法、构造方法和变量。
  • @Qualifier:该注解和@Autowired 注解搭配使用,用于消除特定 bean 自动装配的歧义。
  • JSR-250 Annotations:Spring 支持基于 JSR-250 注解的如下注解,@Resource、@PostConstruct 和@PreDestroy。 

六、SpringMVC 的流程? 

  1. 用户发送请求至前端控制器 DispatcherServlet;
  2. DispatcherServlet 收到请求后,调用 HandlerMapping 处理器映射器,请求获取Handle
  3. 处理器映射器根据请求 url 找到具体的处理器,生成处理器对象及处理器拦截器(若是有则生成)一并返回给 DispatcherServlet;
  4. DispatcherServlet 调用 HandlerAdapter 处理器适配器;
  5. HandlerAdapter 通过适配调用 具体处理器(Handler,也叫后端控制器);
  6. Handler 执行完成返回 ModelAndView;
  7. HandlerAdapter 将 Handler 执 行 结 果 ModelAndView 返 回 给DispatcherServlet ; 
  8. DispatcherServlet 将 ModelAndView 传 给ViewResolver 视图解析器进行解析;
  9. ViewResolver 解析后返回具体View;
  10. DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet 响应用户。


七、Springmvc 的优势:

  1. 能够支持各类视图技术,而不只仅局限于 JSP;
  2. 与 Spring 框架集成(如 IoC 容器、AOP 等);
  3. 清 晰 的 角 色 分 配 : 前 端 控 制 器 (dispatcherServlet) , 请 求 处处理器映射(handlerMapping), 处理器适配器(HandlerAdapter), 视图解析器(ViewResolver)。
  4. 支持各类请求资源的映射策略。 

8. Spring 通知类型使用场景分别有哪些?

  

9.IoC 控制反转设计原理?

具体设计原理以下图:


10.Spring 如何处理线程并发问题?

Spring 使用 ThreadLocal 解决线程安全问题。咱们知道在通常状况下,只有无状态的 Bean 才能够在多线程环境下共享,在Spring 中,绝大部分 Bean 均可以声明为 singleton 做用域。就是由于Spring 对 一 些 Bean ( 如 RequestContextHolder 、
TransactionSynchronizationManager、LocaleContextHolder 等)中非线程安全状态采用 ThreadLocal 进行处理,让它们也成为线程安全的状态,由于有状态的 Bean 就能够在多线程中共享了。

ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。在同步机制中,经过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析何时对变量进行读写,何时须要锁定某个对象,何时释放对象锁等繁杂的问题,程序设计和编写难度相对较大。而 ThreadLocal 则从另外一个角度来解决多线程的并发访问。 ThreadLocal 会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。由于每个线程都拥有本身的变量副本,从而也就没有必要对该变量进行同步了。 ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,能够把不安全的变量封装进 ThreadLocal。

因为 ThreadLocal 中能够持有任何类型的对象,低版本 JDK 所提供的 get()返回的是 Object 对象,须要强制类型转换。但 JDK 5.0 经过泛型很好的解决了这个问题,在必定程度地简化 ThreadLocal 的使用。归纳起来讲,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而 ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不一样的线程排队访问,然后者为每个线程都提供了一份变量,所以能够同时访问而互不影响。 

最后

欢迎你们关注个人公种浩【以Java架构赢天下】,整理了960道2019年多家公司java面试题400多页pdf文档,还有一份本身平时学习整理的Java学习笔记,共500多页,文章都会在里面更新,整理的资料也会放在里面。喜欢文章记得关注我点个赞哟,感谢支持!


个人Java学习笔记(知识点+面试整理)

相关文章
相关标签/搜索