JAVA八股文面试题

1.JDK、JRE、JVM之间的区别

jdk包含jre,jre包含jvm。jvm是java实现整个跨平台最核心的部分,负责运行字节码文件,jre中则还包括一些jvm运行时需要的类库,jdk中则还包括java编译器。

2.hashCode()与equals()之间的关系

如果比较两个对象,通常先调用hashCode()方法获取两个对象的哈希值进行对比,若值不同对象肯定不同,若值相同则会进一步调用equals()方法来最终确定两个对象是不是相等的。

3.String、StringBuffer、StringBuilder的区别

string是不可变的,如果尝试修改会生成新的字符串对象;StringBuffer和StringBuilder则是可变的 ,而且前者线程安全,后者线程不安全,所以单线程环境下StringBuilder效率更高。

4.泛型中extends和super的区别

extends和super是用来限定泛型类型参数的关键字。前者声明一个上界,限定传入的类型必须是该类型或其子类;后者声明一个下界,限定传入的类型必须是该类型或其父类。

5.==和equals方法的区别

==:如果是基本数据类型,则比较他们的值;如何是引用类型,比较的是他们的引用地址。

equals:具体要看各个类重写equals方法后的比较逻辑,比如string类,虽然是引用类型,但是重写后比较的是字符串中各个字符是否全部相等。

6.重载和重写的区别

重载是方法名一样参数列表不同;重写是方法名一样参数列表一样返回类型一样但方法体不一样,但要注意子类方法的访问修饰权限不能小于父类。

7.List和Set的区别

List:有序,按对象插入的顺序保存对象,可重复,允许多个null元素对象,可以使用迭代器(Iterator)取出所有元素,再逐一遍历;还可以使用get(int index)获取指定下标的元素。

Set:无序,不可重复,最多允许有一个null元素对象,取元素时只能使用迭代器(Iterator)取出所有元素,再逐一遍历。

8.ArrayList的底层工作原理

a.在构造ArrayList时,如果没有指定容量,那么内部会构造一个空数组,如果指定了容量,则会构造一个特定容量大小的数组。

b.在添加元素时,会先判断数组容量是否足够,不够则会按照1.5倍扩容,容量够了后才会添加该元素。

c.在添加元素时,如果指定了下标,则先检查下标是否越界,再确认数组容量是否足够,不够则1.5倍扩,然后再将新元素添加到该下标,如果该位置后面还有元素则元素后移。

d.在获取指定下标元素时,先判断下标是否越界,然后从数组中取出该位置元素。

9.ArrayList和LinkedList区别

a.底层数据结构不同,ArrayList是数组,LinkedList是链表。

b.适用场景不同,ArrayList更适合随机查找,LinkedList更适合添加和删除,两者的各个操作下的时间复杂度不同

c.ArrayList和LinkedList都实现了list接口,但是LinkedList还实现了Deque(双端队列)接口,所以后者还能当队列使用。

10.HashMap和HashTable有什么区别,其底层实现原理是什么

区别:

a.HashMap方法没有synchronized修饰,线程非安全,HashTable线程安全。

b.HashMap允许key和value为null,HashTable不允许。

底层实现:

数组+链表,jdk8开始链表高度到8、数组长度超过64,链表转为红黑树,元素内部以Node接点来存储,若后续长度低于6则重新转为链表。key为null时存在下标为0的地方。

11.如何实现一个IOC容器

a.配置文件配置包扫描路径

b.递归包扫描获取.class文件

c.反射、确定需要交给IOC管理的类

d.对需要注入的类进行依赖注入

12.什么是字节码,采用字节码的好处

在java中供虚拟机理解的代码叫做字节码,即扩展名为.class的文件。

java语言通过字节码的方式不仅提高程序的执行效率,而且还保持了解释型语言可移植的特点。

12.java类加载器

jdk自带的有三个类加载器

AppClassLoader:自定义加载器的父类,负责加载classpath下的类文件。

ExtClassLoader:是AppClassLoader的父类加载器,负责加载%JAVA_HOME%/lib/ext文件夹下的jar包和class类。

bootstrap ClassLoader:是ExtClassLoader的父类加载器,默认负责加载%JAVA_HOME%/lib文件夹下的jar包和class类。

13.双亲委托模型

向上委派向下查找。实际上就是查找缓存,是否加载了该类,有直接返回,没有则继续向上;委派到顶层之后,如果还是没有,则到加载路径中查找,有则加载返回,没有则向下查找,一直查到发起加载的加载器为止。

14.Java中的异常

java中的所有异常都来自顶级父类Throwable。

Throwable下有两个子类Exception和Error。

Error是程序无法处理的错误,一旦出现则程序被迫停止。

Exception不会导致程序停止,其又分为RunTimeException运行时异常和CheckedException检查异常,前者会导致当前线程执行失败,后者导致程序编译不通过。

15.GC如何判断对象可以被回收

a.引用计数法:每个对象都有一个引用计数属性,每新增一个引用加1反之减1,当为0时回收。

b.可达性分析法:从GC Roots开始向下搜索,其路径为引用链。当一个对象到GC Roots没用任务引用链项相连,则表明其不可用,可以回收。

16.线程的生命周期及状态

a.创建(New):新创建了一个线程对象。

b.就绪(Runable):线程对象创建后,其他线程调用了该对象的start()方法。改状态的线程位于线程池中,变得可运行,等待获取cpu的使用权。

c.运行(Running):就绪状态的线程获取了cpu,执行程序代码。

d.阻塞(Blocked):线程因为某种原因放弃cpu使用权,暂停运行。知道线程进入就绪状态才有机会继续运行。

e.死亡(Dead):线程执行完毕或因特殊原因结束了run()方法,该线程结束生命周期。

17.sleep()、wait()、join()、yield()区别

a.sleep是Thread类的静态方法,wait则是object类的本地方法。

b.sleep不会释放lock,但是wait会释放,并加入到等待池中。

c.sleep不依赖synchronized,但是wait需要依赖。

d.sleep不需要被唤醒,wait需要。

e.sleep会让出cpu并强制上下文切换,但wait不一定。

f.yield执行后线程直接进入就绪状态,释放cpu的执行权但仍保留执行资格。

g.join执行后线程进入阻塞状态。

18.对线程安全的理解

当多个线程访问一个对象时,如果不进行额外的同步控制或其他的协调操作,调用这个对象的行为都可以获得正确的结果,就可以说这个对象是线程安全的。

19.对守护线程的理解

为所有非守护线程提供服务的线程。其应用场景如下:

a.为其他线程提供服务支持的情况。最经典的就是GC垃圾回收线程。

b.在任何情况下,当程序结束,这个线程必须正常且立刻关闭,就能当做守护线程。

20.ThreadLocal原理及使用场景

ThreadLocal 是一个线程级别变量,每个线程都有一个独立的 ThreadLocal ,在并发模式下是绝对安全的变量。

使用场景:

a.在进行对象夸层传递的时候,使用Threadlocal可以避免多次传递,打破层次间的约束。

b.线程间数据隔离。

c.进行事物操作,用来存储事务信息。

d.数据库连接,Session回话管理。

21.ThreadLocal内存泄漏原因,如何避免

根源:由于ThreadLocalMap的生命周期和Thread一样长,如果没有手动的清除对应key就会导致内存泄漏,而不是因为弱引用。

正确使用方法:

a.每次使用完ThreadLocal都调用它的remove()方法清除数据。

b.将ThreadLocal的变量定义为priivate static ,这样就一直存在Threadlocal的强引用,也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值,进而清除掉。

22.并发、并行、串行区别

a.并发允许两个任务彼此干扰。统一时间点只有一个任务运行,交替执行。

b.并行在时间上是重叠的,两个任务在同一时刻互不干扰的同时执行。

c.串行在时间上不可能发生重叠,前一个任务没搞定,下一个任务只能等待。

23.并发的三大特性

a.原子性:在一个操作中cpu不可以在中途暂停然后再调度,即不被中断,要不全部执行完成,要不都不执行。

b.可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

c.有序性:程序执行的顺序按照代码的先后顺序执行。

使用synchronized关键字可以解决以上三个问题的出现。

24.为什么使用线程池,解释线程池的参数

原因:

a.降低资源消耗。提高线程利用率,降低线程创建和销毁的消耗。

b.提高响应速率。任务来了直接有线程可以使用,而不是先创建再执行。

c.提高线程的可管理性。线程是稀缺资源,使用线程池可以统一分配调优监控。

参数:

corePoolSize:核心线程数,其创建后不会被消除,属于常驻线程。

maxnumPoolSize:最大线程数,表示最大允许被创建的线程数。

keepAliveTime、unit:超出核心线程之外的线程的空闲存活时间,可以通过setKeepAliveTime来设置空闲时间。

workQueue:用来存放待执行的任务。当核心线程都已被使用,还有任务进来则全部放入队列中,直到队列满后任务若还在继续,就会创建新的线程。

ThreadFactory:线程工厂,用来生产线程执行任务。

Handler:任务拒绝策略。有两种情况,第一,调用shutdown等方法关闭线程池后,即使其中还有未完成的任务,但此时想提交任务就会遭到拒绝;第二,已达到最大线程数,线程池没有能力处理新提交的任务也会拒绝。

25.线程池中阻塞队列的作用,为什么是先添加队列而不是先创建最大线程

作用:

a.普通的队列只能作为一个长度有限的缓冲区,如果超出其长度就无法保存该任务,但是阻塞队列可以通过阻塞保留住当前想要继续加入的任务。

b.阻塞队列自带注射唤醒功能,可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入wait状态,释放cpu资源。

原因:

在创建新线程的时候,是要获取全局锁的,这个时候其它的就得阻塞,影响了整体效率。

26.线程池中线程复用原理

线程池将线程和任务进行解耦,线程是线程,任务是任务,摆脱了之前通过Thread创建线程时的一个线程必须对应一个任务的限制,而是让每个线程去执行一个“循环任务”,不停的检查是否有任务需要被执行,有则调用任务中的run方法。

27.spring是什么

Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。

28.谈谈对AOP的理解

将程序中的交叉业务逻辑(比如安全、日志、事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。AOP可以对某个对象或某些对象的功能进行增强,可以在执行某个方法之前或之后额外做一些事情。

29.谈谈对IOC的理解

实际上就是一个容器map,key-value存储配置文件里的bean节点、类似(@component)注解的类对象,在项目启动时,通过反射读取配置文件里的bean节点及注解类创建对象放入map中。在没有引入IOC时,对象A依赖B,在A初始化或运行中必须主动创建B或使用已有的B,但引入IOC后,当A需要B时,IOC容器会主动创建B,获得依赖对象的过程由自身管理变为了由IOC容器主动注入,这就是控制反转和依赖注入。

30.BeanFactroy和ApplicationContext的区别

ApplicationContext是BeanFactroy的子接口,提供了更完整的功能:

a.继承了MessageSource,因此支持国际化。

b.统一的资源文件访问方式。

c.提供在监听中注册bean的事件。

d.同时加载多个配置文件。

e.载入多个(有继承关系)上下文,使得每个上下文都专注于一个特定的层次,比如应用的web层。

区别:

a.BeanFactroy采用的是延迟加载来注入Bean的,即只有用到了某个Bean时才进行加载实例化,ApplicationContext则是在容器启动时一次性创建所有的Bean,但是后者相对占用内存,如果配置的Bean较多,程序启动会很慢。

b.BeanFactroy通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

c.BeanFactroy和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但是前者需要手动注册,后者则是自动注册。

31.描述一下SpringBean的生命周期

a.解析类得到BeanDefinition。

b.如果有多个构造方法,则要推断构造方法。

c.确定好构造方法后,进行实例化得到一个对象。

d.对对象中加了@Autowired注解的属性进行填充。

e.回调Aware方法,比如BeanNameAware、BeanFactoryAware。

f.调用BeanPostProcessor的初始化前的方法。

g.调用初始化方法。

h.调用BeanPostProcessor的初始化后的方法,在这里会进行AOP。

i.如果当前创建的Bean是单例的则会把bean放入单例池。

j.使用bean。

k.Spring容器关闭时调用DisposableBean中的destory()方法。

32.解释下Spring支持的几种bean的作用域

a.单列(Singleton):默认,每个容器中只有一个bean实例。

b.原型(Prototype):为每一个bean请求提供一个实例。

c.请求(Request):bean被定义为在每个http请求中创建一个单例对象,也就是说单个请求中都会复用这一个单例对象。

d.会话(Session):确保每个session中有一个bean实例,在session过期后,bean会随之失效。

e.全局会话(GlobalSession):在Portlet环境下使用,代表全局会话的Bean。

33.Spring中的单例bean是线程安全的吗

不是线程安全的,框架并没有对bean进行多线程的封装。最简便的就是改变bean的作用域为原型模式,或者使用Threadlocal把变量变成线程私有的,或者加锁。

34.Spring框架中都用了哪些设计模式

a.简单工厂:spring中的BeanFactory就是简单工厂的体现,根据传入的一个唯一标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建要根据具体情况判断。

b.工厂方法:实现了FactoryBean接口的bean是一类叫做factory的bean,特点是sping会在使用getBean()调用获得改bean时,会自动的调用bean.getObject()方法,返回的不是factory这个bean。

c.单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

d.适配器模式:Spring定义了一个适配器接口,使得每一个Controller有一种对应的适配器实现类,让适配器代替Controller执行相应的方法。

e.装饰器模式:动态的给一个对象添加一些额外的职责。

f.动态代理、观察者模式、策略模式。

35.Spring事务的实现方式和原理以及隔离级别

实现方式:编程式和申明式,@Transactional注解就是申明式的。

原理:在方法上加上@Transactional注解,就可以开启事务,spring会就这个类生成一个代理对象,当在使用这个代理对象的方法时,如何这个方法上有@Transactional注解,那么代理逻辑会把事务的自动提交设置为false,然后再去执行原本业务逻辑,当其中没有出异常时,代理逻辑就会把事务提交,如果出现异常则会回滚。

隔离级别:spring的隔离级别就是数据库的隔离级别:外加一个默认级别

a.DEFAULT:这是默认的隔离级别,表示使用数据库默认的隔离级别。

b.READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、不可重复读和幻读。

c.READ_COMMITTED:保证一个事务不能读取另一个事务已修改但未提交的数据,可避免脏读,但可能导致不可重复读和幻读。

d.REPEATABLE_READ:确保事务可以多次从一个字段读取相同的数据,在事务处理过程中,若该字段被其他事务更新,该事务将不会检测到,但是可以防止不可重复读和幻读。

e.SERIALIZABLE:最高的隔离级别,所有事务串行化执行,可以避免所有隔离问题,但是性能最差。

36.Spring事务传播机制

a.required(默认的):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务。

b.support:当前存在事务,则加入当前事务,当前没有事务,就以非事务执行。

c.mandatory:当前存在事务,则加入,不存在则抛异常。

d.requirse_new:创建一个新事务,若存在当前事务,则挂起当前事务。

e.not_support:以非事务方式执行,若存在当前事务,则挂起当前事务。

f.never:不使用事务,若当前事务存在,则抛异常。

g.nested:如果当前事务存在,则在嵌套事务中执行,否则required一样。

37.Spring事务什么时候会失效

Spring事务的原理是AOP,失效就是AOP不起作用,有以下几个原因:

a.发生自调用,类里面使用this调用本类的方法。

b.方法不是public的

c.数据库不支持事务。

d.没有被spring管理。

e.异常被吃掉,事务不会回滚(或抛出的异常没有被定义,默认为RuntimeException)

38.什么的是bean的自动装配,它有哪些方式

bean的自动装配指的是bean的属性值在进行注入的时候通过某种特定的规则和方式去容器中查找,并设置到具体的对象属性中,定义“autowire”主要有五种方式:

a.no :缺省情况下,自动配置是通过“ref”属性手动设定,在项目中最常用。

b.byName :根据属性名称自动装配。如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。

c.byType :按数据类型自动装配,如果bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。

e. constructor :在构造函数参数的byType方式。

f.autodetect :如果找到默认的构造函数,使用“自动装配用构造”; 否则,使用“按类型自动装配”。

39.SpringBoot、SpringMVC、Spring有什么区别

Spring是一个IOC容器,用来管理Bean,使用依赖注入实现控制反转,可以很方便的整合各种框架,提供AOP机制。

SpringMVC是Spring对web框架的一个解决方案,提供了一个总的前段控制servlet,用来接收请求,然后定义了一套由路由及适配执行handle,将handle结果使用视图解析技术生成视图展示给前端。

SpringBoot是一个spring的一个快速开发工具包,能够让程序员更方便、快捷的开发Spring+SpringMVC应用,简化了配置,整合了一系列的解决方案,可以开箱即用。

40.SpringMVC工作流程

a.用户发送请求至前端控制器DispatcherServlet。

b.DispatcherServlet收到请求调用HandlerMapping处理器映射器。

c.处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器及处理拦截器(如果有则生成)一并返回给DispatcharServlet。

d.DispatcharServlet调用HandleAdapter处理适配器。

e.HandleAdapter经过适配器调用具体的处理器(Controller,也叫后端控制器)

f.Controller执行完成返回ModelandView。

g.HandleAdapter将Controller执行结果ModelandView返回给DispatcherServlet。

h.DispatcherServlet将ModelandView传给ViewResloer视图解析器。

i.ViewResloer解析后返回具体的View。

j.DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

k.DispatcherServlet响应用户。

41.SpringBoot自动配置原理

主要使用@Import + @Configuration + Srping spi实现,自动配置类由各个starter提供,使用@Configuration + @Bean定义配置类,放到MEAT-INF/spring.factories下,使用Srping spi扫描MEAT-INF/spring.factories下的配置类,使用@Import导入自动配置类。

42.mybatis的优缺点

优点:

a.基于sql语句编程相当灵活,不会对应用程序或者数据库的现有设计造成影响,sql写在xml里面,解除了sql与程序代码的耦合,便于统一管理;提供xml标签,支持编写动态sql语句,并可重用。

b.与jdbc相比,减少了%0%以上代码量,不需要手动开关连接。

c.很好的与各种数据库兼容。

d.能够与spring很好的集成。

e.提供映射标签,支持对象与数据库ORM字段的关系映射;提供对象关系映射标签,支持对象关系组件维护。

缺点:

a.sql语句的编写工作量大。

b.sql语句依赖数据库,导致数据库移植性差,不能随意更换数据库。

43.MyBatis和Hibernate有哪些不同

a.开发速度:Hibernate的真正掌握要比MyBatis难一些,如果项目中基本没有用到复杂查询,则用Hibernate会跟快一些,反之则是MyBatis。

b.开发工作量:针对高级查询,MyBatis要手动编写SQl语句,而Hibernate可以更专注于业务流程。

c.sql优化:MyBatis可以更方便的优化sql,Hibernate的查询会将所有字段查出,这点会有性能消耗。

d.对象管理:Hibernate是完整的对象/关系映射解决方案,提供了对象状态管理的功能,而MyBatis需要用户对对象自己进行详细的管理。

44.#{}和${}的区别

#{}是预编译处理、是占位符;${}是字符串替换、是拼接符。

mybatis在处理#{}时,会将sql中的#{}替换为?,调用PreparedStatement来赋值。

mybatis在处理${}时,会将sql中的#{}替换成变量的值,调用Statement来赋值。

#{}的替换是在DBMS中,变量替换后,#{}对应的变量自动加上单引号。

${}的替换是在DBMS外,变量替换后,${}对应的变量不会加上单引号。

使用#{}可以有效防止sql注入,提高系统安全性。

45.索引的基本原理

原理:把无序的数据变成有序的查询。

a.把创建了索引的列的内容进行排序。

b.对排序结果生成倒排表。

c.在倒排表内容上拼上数据地址链。

d.在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据。

46.myql聚簇和非聚簇索引的区别

都是B+树的结果。

聚簇索引:将数据存储与索引放到一起,并且按照一定顺序组织。

非聚簇索引:叶子节点不存储数据,存储的是数据行地址。

47.mysql索引的数据结构,各自优势

索引的数据结构和具体存储引擎的实现有关,在mysql中使用较多的索引有hash索引、B+树索引等,InnoDb存储引擎的默认索引实现为B+树索引。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择B+树索引。

48.索引设计的原则

查询更快,占用空间更小。

a.适合索引的列是出现在where子句中的列,或者连接子句中指定的列。

b.基数较小的类没必要在此列建索引。

c.使用短索引。

d.不要过度索引。

e.定义有外键的数据列一定要建立索引。

f.更新频繁的字段不适合建立索引。

g.不能有效区分数据的列不适合建索引。

h.尽量扩展索引,不要新建索引。

i.对查询中很少涉及的列,重复值较多的列不要建索引。

j.对于定义为text、image、bit的数据类型的列不要建索引。

49.mysql锁的类型有哪些

基于锁的属性分类:共享锁、排它锁。

基于锁的粒度分类:行级锁(InnoDb)、表级锁(InnoDb、MYISAM)、页级锁(BDB引擎)、记录锁、间隙锁、临建锁。

基于锁的状态分类:意向共享锁、意向排它锁。

50.事务的基本特性和隔离级别

事务基本特性ACID分别是:

原子性:一个事务中的操作要么全部成功要么全部失败。

一致性:数据库总是从一个一致性的状态转换到另外一个一致性的状态。

隔离性:一个事务的修改在最终提交前,对其他事务是不可见的。

持久性:一旦事务提交,所做的修改就会永久保存到数据库中。

隔离性有4个隔离级别,分别是:

a.read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫做脏读。

b.read commit 读已提交,两次读取结果不一致,叫做不可重复读。

c.repeatable read 可重复读,这是mysql默认的级别,每次读取结果一样,但是有可能产生幻读。

d.serializable 串行,一般不会使用,他会给每一行数据加锁,会导致大量超时和锁竞争问题。

51.关心过业务系统里面的sql耗时吗,统计过慢查询吗,对慢查询都怎么优化过

在业务系统中,除了使用主键进行的查询,其它都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我没。

优化的三个方面:

a.首先分析语句,看看时否load了额外的数据,可能时查询了多余的行并且抛弃掉了,可能是加载了结果中不需要的列,对语句进行分析及重写。

b.分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或修改索引,使得语句可以尽可能的命中索引。

c.如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

52.ACID靠什么保证

A原子性由undo log日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql。

C一致性由其它三大特性保证、程序代码要保证业务上的一致性。

I隔离性由MVCC(多版本控制)来保证。

D持久性由内存+redo log来保证,mysql修改数据同时在内存和redo log记录这次的操作,宕机的时候可以从redo log恢复。

53.什么是MVCC

多版本并发控制:读取数据时通过一种类似快照的方式将数据保存下来,这样读锁和写锁不冲突了,不同的事务session会看到自己特定版本的数据,版本链。

54.简述MYISAM和InnoDB的区别

MyISAM:

不支持事务,但是每次查询都是原子的;

支持表级锁,即每次操作是对整个表加锁;

存储表的总行数;

一个MYISAM表有三个文件:索引文件、表结构文件、数据文件;

采用非聚簇索引,索引文件的数据域存储指向数据文件的指针。

 InnoDB:

支持ACID的事务,支持事务的4种隔离级别;

支持行级锁及外键约束;

不存储总行数;

一个InnoDB引擎存储在一个文件空间中,也可能为多个,受操作系统文件大小的限制;

主键索引采用聚簇索引,索引的数据域存储数据文件本身,辅索引的数据域存储主键的值。

55.简述mysql中索引类型及对数据库的性能的影响

普通索引:允许被索引的数据列包含重复的值。

唯一索引:可以保证数据记录的唯一性。

主键:是一种特殊的唯一索引,在一张表中只能定义一个主键索引。

联合索引:索引可以覆盖多个数据列,如INDEX(columnA,columnB)。

全文索引:通过建立倒排索引,可以极大提升检索效率,解决判断字段包含问题。

索引可以极大的提升数据的查询速度。

但是会降低插入、删除、更新表的速度,因为执行这些写操作时还要操作索引文件。

索引需要占用物理空间,如果建立聚簇索引那需要的空间更大,如果非聚簇索引很多,一旦聚簇索引改变,那么所有的非聚簇索引都会跟着变。

56.redis中RDB和AOF机制

RDB:Redis DataBase,在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,现将数据集写入临时文件,写入成功后再替换之前的文件,用二进制压缩存储。

优点:整个Redis数据库将只包含一个dump.rdb,方便持久化;容灾性好,方便备份;性能最大化;相对于数据集大时比AOF启动效率高。

缺点:数据安全性低;

AOF:Append Only File,以日志的形式记录服务器所处理的每一个写、删除操作,查询不会记录,以文本的方式记录,可以打开文件查看详细的过程。

优点:数据安全,其提供了三总同步策略,每秒同步、每修改同步、不同步;通过append模式写文件,即使中途服务宕机也不会破坏已存在内容,可以通过redis-check-aof工具解决数据一致性问题;AOF的rewrite模式能够定期对AOF文件进行重写,达到压缩目的。

缺点:AOF文件比RDB文件大,且恢复速度慢;数据集大的时候比RDB启动效率低;运行效率也没有RDB高。

57.Redis过期键的删除策略

惰性过期:只有当访问了一个key时,才会判断该key是否已过期,过期则清除。

定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。

58.Redis线程模型,单线程为什么快

redis基于Reactor模式开发了网络事件处理器,这个处理器又叫做文件事件处理器,因为它是单线程的,所以redis才叫单线程的模型,它采用IO多路复用机制来同时监听多个Socket,根据Socket上的事件类型来选择对应的事件处理器处理该事件。

单线程快的原因:

a.纯内存操作。

b.核心是非阻塞的IO多路复用机制。

c.单线程反而避免了多线程频繁上下文切换而带来的性能问题。

59.缓存雪崩、缓存穿透、缓存击穿

缓存雪崩:缓存同一时间大面积的失效,后面的请求都会落在数据库上,造成数据库短时间内承受大量请求而崩溃掉。

解决方案:缓存的过期时间设置随机;给缓存数据增加缓存标记;缓存预热。

缓存穿透:缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩溃掉。

解决方案:接口层增加校验;采用布隆过滤器。

缓存击穿:缓存中没有但数据库中有的数据,由于并发用户特别多,同时读缓存没读到数据,又同时去数据库取数据,引起数据库压力瞬间增大。

解决方案:设置热点数据永远不过期。

60.Redsi集群方案

哨兵模式:

集群监控,负责监控redis master 和 slave 进程是否正常工作。

消息通知,如果某个redis实例故障,那么哨兵负责发送消息报警通知给管理员。

故障转移,如果master node挂掉了,会自动转移到 slave node上。

配置中心,如果故障转移发生了,通知client客户端新的master地址。

哨兵用于实现redis集群的高可用,本身也是分布式,作为一个哨兵集群去运行,互相协同工作。

61.redis主从复制的核心原理

a.一个从数据库在启动后,会向主数据库发送SYNC命令。

b.主数据库在接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存快照期间接收到的命令缓存起来。在该持久化过程中会生成一个.rbd快照文件。

c.在主数据库快照执行完成后,Redis会将快照文件和所有缓存的命令以.rdb快照文件的形式发送给从数据库。

d.从数据库收到主数据库的.rdb快照文件后,载入该快照文件到本地。

e.从数据库执行载入后的.rdb快照文件,将数据写入内存中。

【以上步骤称为复制初始化】

f.在复制初始化结束后,主数据库在每次收到写命令时都会将命令同步给从数据库,从而保证主从数据库的数据一致。

62.CAP理论,BASE理论

Consistency(一致性):更新操作成功并返回给客户端后,所有节点在同一时间的数据完全一致。

Availability(可用性):即服务一直可用,而且是正常响应时间。

Partition Tolerance(分区容错性):即分布式系统在遇到某些节点或网络分区故障时,仍然能够对外提供满足一致性和可用性的服务。

BASE是基本可用、软状态和最终一致性。核心思想:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。

63.负载均衡算法、类型

a.轮询法:将请求按顺序轮流的分配到后端服务器。

b.随机法:通过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台。

c.源地址哈希法:根据获取客户端的ip地址,通过哈希函数计算得到一个值,用该值对服务器列表的大小进行取模运算,得到的结果就是客户端要访问的服务器序号。

d.加权轮询法:给高配置、负载低的机器配更高的权重,让其处理更多的请求,反之则分配较低权重,降低其负载。

e.加权随机法:和加权轮询类似,但是其是按照权重随机请求后端服务器而非顺序。

f.最小连接数法:根据后端服务器当前的连接情况,动态的选取其中当前积压连接数最少的一台服务器来处理当前请求。

类型:

a.DNS方式实现负载均衡。

b.硬件负载均衡:F5、A10。

c.软件负载均衡:Nginx等。

64.分布式架构下,Session共享有什么方案

a.采用无状态服务,抛弃session。

b.存入cookie(有安全风险)。

c.服务器之前进行session同步,保证每个服务器上都有全部session信息,不过当服务器多时,会出现延迟或失败。

d.ip绑定策略,同一个ip只能在指定的同一个机器访问。

e.使用redis存储。

65.简述RPC、RMI

RPC:在本地调用远程的函数,远程过程调用,可以跨语言实现。

RMI:远程方法调用,java中用于实现RPC的一种机制,直接或间接实现接口 java.rmi.Remote成为存在于服务器端的远程对象,供客户端访问并提供一定的服务,远程对象必须实现java.rmi.server.UniCastRemoteObject类,这样才能保证客户端远程访问获得远程对象时,该远程对象会将自身的一个拷贝以socket的形式传给客户端。

66.分布式id生成方案

a.uuid

当前日期和时间+时钟序列+全局唯一的IEEE机器识别码

优点:代码简单,性能好,保证唯一

缺点:id无序,存储性能差,可读性差,有信息安全问题如泄露mac地址。

b.数据库自增序列

优点:实现简单,成本小,id数字化,单调自增。

缺点:强依赖DB,存在单点问题,性能有限,无法抗高并发场景。

c.雪花算法

生成一个64bit的整形数字,第一位符号位固定为0、41位时间戳、10位workId、12位序列号,位数可以有不同实现。

优点:性能好,整个Id趋势递增,灵活度高。

缺点:强依赖于时钟,如果时钟回拨,会导致重复的id生成。

67.如何实现接口的幂等性

a.唯一id。每次操作,都根据操作和内容生成唯一的id,在执行前先判断id是否存在,如果不存在则执行后续操作,并保存到数据库或者redis等。

b.服务端提供发送token的接口,业务调用接口前先获取token,然后调用业务接口请求时,把token携带过去,服务器判断token是否存在redis中,存在表示第一次请求,可以继续执行业务,最后需要把redis中的token删掉。

c.建去重表。将业务中有唯一标识的字段保存到去重表,如果表中存在,则表示已经处理过了。

d.版本控制。增加版本号,当版本号符合时,才能更新到数据。

e.状态控制。

68.简述ZAB协议

ZAB协议是为分布式协调服务 Zookeeper专门设计的一种支持崩溃恢复的原子广播协议,实现分布式数据一致性。

ZAB协议包括两种基本的模式:崩溃恢复和消息广播。

消息广播:集群中所有的事务请求都由Leader节点处理,其他服务器为Follower,Leader将客户端的事务请求转换为事务Proposal并分发给集群中所有的Follower,完成广播后等待反馈,若过半数则再次广播Commit信息,从而提交事务。

崩溃恢复:在初始化集群、Leader崩溃、Leader失去了半数机器的支持的情况下,开始新一轮的Leader选举,选举产生的Leader会与过半的Follower进行同步使数据一致。

69.简述ZK的命名服务、配置管理、集群管理

命名服务:通过指定的名字来获取资源或服务地址。

配置管理:把程序的配置信息保存在zk的znode节点下,当你要修改配置,即znode发生变化,利用watcher通知给各个客户端,从而更改配置。

集群管理:监控集群机器的状态,添加或者删除机器。

70.讲一下Zookeeper watch机制

客户端可以通过在znode上设置watch,实现实时监听znode的变化。

watch事件时一个一次性的触发器,当被设置了watch的数据发生改变,服务器就会将这个改变发送给设置了watch的客户端。

父节点的创建、修改、删除以及子节点的创建、删除都会触发watch事件。

一旦触发就会移除,再次使用需要重新注册,但3.6.0默认持久递归,可以触发多次。

该通知只会告知发生了事情,不会告知具体内容,以减轻服务带宽和压力。

watch机制包括三个角色:客户端线程、客户端的WatchManager、zookeeper服务器,

客户端向zookeeper服务器注册一个watch监听,把这个监听信息存储到WatchManager中,当zookeeper的节点发生变化时,会通知客户端,客户端会调用相应watch对象中的回调方法。

71.ZK和Eureka的区别

zk是CP设计(强一致性),目标是一个分布式的协调系统,用于进行资源的统一管理。当节点崩溃后,重新进行leader选举时,服务是不可用的。

eureka是AP设计(高可用),目标是一个服务注册发现系统,专门用于微服务的服务发现注册。其中各个节点都是平等的,几个节点挂掉并不影响整体,剩余还可以提供注册和查询服务。

72.SpringCloud和Dubbo的区别

底层协议:springcloud基于http协议,dubbo基于tcp协议,dubbo的性能相对较好。

注册中心:springcloud使用eureka,dubbo推荐使用zookeeper。

模型定义:springcloud将一个应用定义为一个服务,dubbo则是将一个接口定义为一个服务。

springcloud是一个生态,而dubbo是springcloud生态中关于服务调用的一种解决方案(服务治理)。

73.什么是Hystrix

分布式容错框架,阻止故障的连锁反应,实现熔断;快速失败,实现优雅降级;提供实时的监控和告警。

a.通过HystrixCommand将所有的外部系统包装起来,整个包装对象时单独运行在一个线程之中。

b.超时请求应该超过你定义的阈值。

c.为每个依赖关系维护一个小的线程池(或信号量),如果它变满了,那么依赖关系的请求将立刻被拒绝,而不是排队等待。

d.统计成功、失败、超时和线程拒绝。

e.打开断路器可以在一段时间内停止对特定的服务的所有请求,如果服务的错误百分比通过阈值,手动或自动的关闭断路器。

f.当请求被拒绝、连接超时或者断路器打开,执行fallback逻辑。

g.近乎实时监控指标和配置变化。

74.springcloud核心组件及其作用

Eureka:服务注册发现

注册:每个服务都向Eurka登记自己的服务信息,eureka将各个服务维护在一个服务清单中(双层Map,第一层key服务名,第二层key实例名,value服务地址加端口),同时对服务维持心跳,剔除不可用的。

发现:eureka注册的服务之前调用通过服务名向注册中心咨询,并获取所有的服务实例清单,然后实现服务的请求访问。

Ribbon:负载均衡,基于http发起请求,通过调用服务名的地址来实现。

Feign:基于feign的动态代理机制,根据注解和选择的机器,拼接请求url地址,发起请求。

Hystrix:发起请求时通过hystrix的线程池来走的,不同服务走不同的线程池,实现了不同服务调用的隔离,通过统计接口超时次数返回默认值,实现服务熔断和降级。

Zuul:如果前端、移动端要调用后端系统,统一从Zuul网管进入,由Zuul网管转发请求给对应的服务,通过与Eureka进行整合,将自身注册为Eureka下的应用,从Eureka下获取所有服务的实例,来进行服务的路由,其还提供的有一套过滤机制。

75.Dubbo的整体架构

五个角色:

注册中心registry:服务注册与发现。

服务提供者provider:暴露服务。

服务消费者consumer:调用远程服务。

监控中心monitor:统计服务的调用次数和调用时间。

容器container:服务允许容器。

调用流程:

a.container容器负责启动、加载、运行provider。

b.provider在启动时,向registry中心注册自己提供的服务。

c.consumer在启动时,向registry中心订阅自己所需要的服务。

d.registry返回服务提供者列表给consumer,如果有变更,registry将基于长链接推送变更给consumer。

e.consumer调用provider服务,基于负载均衡算法进行调用

f.consumer调用provider的统计基于短链接定时每分钟一次统计到monitor。

76.简述RabbitMQ的架构设计

Broker:rabbitmq的服务节点。

Queue:队列,是rabbitmq的内部对象,用于存储信息。

Exchange:交换器。生产者将消息发送到Exchange,由交换器将消息路由到一个或多个队列中,如果路由不到,或返回给生产者,或直接丢弃,或做其他处理。

RoutingKey:路由Key。生产者将消息发送给交换器时,一般会指定一个rountingkey,用来指定这个消息的路由规则。这个key需要与交换器类型和绑定键BindingKey联合使用才能生效。

交换器和绑定器是多对多的关系。

信道:建立在Connection之上的虚拟连接。当应用程序与Rabbit Broker建立TCP连接时,客户端紧接着可以创建一个AMQP信道,每个信道都会被指派一个唯一的id。RabbitMQ处理的每条AMQP指令都是通过信道完成。

77.RabbitMQ如何确保消息发送和消息接受

发送方确认机制:

信道需要设置为confirm模式,在信道上发布的消息都会分配一个唯一的id,一旦消息被投递到queue,信道会发送一个确认给生产者(包含消息唯一id),如果rabbitmq发生内部错误从而导致消息丢失,会发送一条nack(未确认)给生产者。所有被发送的消息都将被ack或nack一次,发送方确认模式是异步的,生产者在等待确认的时候可以继续发送,当确认消息到达生产者时,生产者回调方法会被触发。

接收方确认机制:

消费者在声明队列时,可以指定noAck参数,当该参数为false时,RabbitMQ会等待消费者显示发回ack信号后才从内存中移去消息,否则消息被消费后会立即删除。RabbitMQ不会为未接收的消息设置超时时间,它判断此消息是否需要重新投递给消费者的唯一依据是该消费者连接是否断开。如果消费者返回接收之前断开了连接,RabbitMQ会重新分发给下一个订阅的消费者(可能存在重复消费的隐患,需要去重)。

78.RabbitMQ事务消息

通过将信道(Channel)设置为事务模式,所有发送到该通道的消息都将在提交事务之前被缓存,并且在提交事务后才会被投递到交换机中。如果事务提交失败,可以进行事务回滚,使消息不会被发送。

a.channel.txSelect(),通知服务器开启事务模式,服务端会返回Tx.Select-Ok;

b.发布消息到交换机:channel.basicPublish(…);

c.提交事务:channel.txCommit();

d.Broker 回复 Tx.Commit - Ok ,确认事务提交;

e.Broker回复超时或者出现异常回滚事务:channel.txRollback()。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值