接口和抽象类的区别?

  • 抽象类可以存在普通成员函数,而接口只能存在public,abstract;
  • 抽象类的成员变量可以是各种类型,而接口的成员变量只能是public static final 类型的
  • 抽象类只能继承一个,接口可以实现多个

接口的设计目的是对类的行为进行约束(规定可以有什么行为),强制要求不同的类具有相同的行为。只约束行为的有无,但不对如何实现进行限制

抽象类的设计目的是代码复用,当不同的类具有相同的行为,而一部分行为的实现方式一致时,可以让这些类派生出一个抽象类,达到代码复用的目的。那些类不一致的行为可以留给子类各自实现。抽象类不允许实例化。

ArrayList与LinkdList的区别?

ArrayList:基于动态数组,连续内存存储,适合下标访问(随机访问)

LinkedList:基于链表,存储在分散的内存中,适合做数据的插入,删除,不适合查询,必须使用iterator遍历

List 和 Set 的区别?

List : 有序,按对象进入的顺序保存对象,可重复,允许多个null元素对象,可以使用iterator取出全部对象,也可以使用get(int index) 获取指定下标的元素。
Set: 无序,不可重复,最多允许一个null元素对象,取元素时只能用iterator接口取得所有元素,再逐一遍历各个元素。

Thread、Runable 的区别?

Thread 是类,Runable是接口
Thread实现Runable,实质是继承关系,都会new Thread,然后执行run方法。

线程安全的理解?

不是线程安全,是内存安全,堆是共享内存,可以被说有的线程访问。
当多个线程访问一个对象是,如果不用额外的同步控制和其他的协调操作,调用这个对象的行为都可以获取正确的结果,我们就说这个对象是线程安全。 

堆是进程和线程共有的空间,分为全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是用完了要还给系统,要不然就是内存泄漏。

栈是每个线程独有的,保存期运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立,因此,栈是线程安全的。操作系统在切换线程的时候自动切换栈,栈空间不需要在高级语言里面显式的分配和释放。

Spring是什么?

轻量级开源的J2EE框架;
是一个容器框架,用来装JavaBean(Java对象);
中间层框架,起一个连接作用(比如说吧struct和hibernate粘合在一起运用);
让我们的企业开发更快,更简洁。

轻量级的控制反转(IOC)和面向切面的(AOP)框架

  1. 轻量级:从大小和开销方面而言Spring都是轻量级的
  2. IOC:通过控制反转(ioc)的技术来达到松耦合的目的
  3. AOP:分离应用的业务逻辑和系统级服务进行内聚式的开发
  4. 容器:包含并管理应用对象(Bean)的配置和生命周期
  5. 框架:简单的组件配置,组合成复杂的应用

Aop的理解?

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

Ioc的理解?

容器概念:ioc就是一个容器,实际上就是一个map(key,value),里面存的是各种对象(在xml里配置的bean节点,@repository,@service,@controller,@component)

在项目启动的时候会读取配置文件里的bean节点,根据全限定类名使用反射创建对象放到map里,或者扫描到打上上述注解的类通过反射创建对象放到map里。
然后系统启动的时候读取xml节点的ref属性根据id,或者根据注解(@autowired,@resource)在代码里需要用到里面的对象时,通过DI注入

控制反转:
引入Ioc容器之前:对象A依赖对象B,主动创建对象B
引入ioc容器之后:对象A需要对象B,ioc容器主动创建对象B注入到对象A需要的地方
控制反转:前后对比,对象A获取依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒。
对象的控制权全部上缴给"第三方"IOC容器,IOC容器成为了系统的关键核心,关联系统中的所有对象一起发挥作用。

依赖注入:实现IOC的方法,有IOC容器在运行期间,动态将某种依赖关系注入到对象之中。

Bean

Bean是什么?

bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。

  • 基于 XML 的配置文件

  • 基于注解的配置

  • 基于 Java 的配置

BeanFactory和ApplicationContext有什么区别?

ApplicationContext是BeanFactory的子接口
ApplicationContext提供更完整的功能:

  1. 继承了MessageSource,因此支持国际化。
  2. 统一的资源文件访问形式。
  3. 提供在监听器中注册bean的事件。
  4. 同时加载多个配置文件。
  5. 载入多个(有继承关系)上下文,使得每一个上下文都专注一个特定的层次,比如应用的web层。
  • BeanFactory采用延迟加载形式注入Bean,即只有在使用某个Bean(调用getBean()),才对该Bean进行加载实例化。启动后只有在使用的时候才能发现存在的Spring的配置问题,
  • ApplicationContext,容器启动时,一次性创建了所有的Bean(启动时就可以发现Spring中存在的配置错误,有利于检查所依赖属性是否注入),Application启动后预载入所有的单实例Bean,需要的时候不用等待。
  • Application占用内存不足,程序配置Bean较多时,启动越慢。
  • BeanFactory通常以编程方式创建,ApplicationContext可以以声明的方式启动,如使用ContextLoader
  • 都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,区别:BeanFactory需要手动注册,ApplicationContext则是自动注册

BeanPostProcessor接口回调对应的主体是bean,其可以在bean实例化以后但是在调用其初始化方法前后进行回调以达到对bean进行处理的效果。
BeanFactoryPostProcessor的主体是BeanFactory,并且该接口中只定义了一个方法,其将会在ApplicationContext内部的BeanFactory加载完bean的定义后,但是在对应的bean实例化之前进行回调。所以通常我们可以通过实现该接口来对
实例化之前的bean定义进行修改。

Bean生命周期?

  1. 解析类得到BeanDefinition
  2. 如果有多个构造函数,则要推断构造方法
  3. 实例化得到一个对象
  4. 对对象中加了@Autowired注解的属性进行属性填充
  5. 回调Aware方法,比如BeanNameAware,BeanFactoryAware(Aware接口也是为了能够感知到自身的一些属性
  6. 调用BeanPostProcessor的初始化前的方法
  7. 调用初始化方法init
  8. 调用BeanPostFactoryProcessor初始后的方法,在这里会进行Aop
  9. 如果创建的Bean是单例则会放入单例池
  10. 使用bean
  11. Spring容器关闭时调用DisposableBean的Destory方法

Bean作用域

singleton默认:每个容器只有一个bean的实例,单例的模式由BeanFactory自身来维护。该对象的生命周期与Spring Ioc容器一致(第一次被注入时创建)
prototype原型模式,为每一个bean请求创建一个实例。在每次注入时都会创建一个新的对象
request bean被定义为在每个HTTP请求中创建一个单例对象,也就是说单个请求中都会复用这一个单例对象
session与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效
applicationbean被定义为在servletContext的声明周期中复用一个单例对象
websocketbean被定义为在websocket的生命周期复用一个单例对象
global-session全局作用域

Spring单例Bean是线程安全?

非线程安全,没有进行多线程封装处理。

怎么保证?改变bean的作用域,把singleton改为prototype,相当于每次请求是new Bean()

Springboot 、 SpringMVC 、 Spring 区别?

Spring:
IOC 容器,用来管理Bean,使用依赖注入实现控制反转,方便整合各种框架;
提供AOP机制弥补OOP的代码重复问题,将不同类不同方法中的共同处理抽取成切面,自动注入给方法执行,比如日志,异常等;

SpringMVC:spring 对web框架的一个解决方案,提供一个总得前端控制器Servlet,接收请求,然后定义了一套路由策略(url到handle的映射),及适配执行handle,将handle结果使用视图解析技术生成视图给前端。

Springboot:spring提供的一个快速开发工具包,更方便,更快捷的开发spring+springmvc应用;
简化了配置,整合了一系列的解决方案(starter机制)、redis、monggodb、es,开箱即用

事务的基本特征和隔离级别

ACID

  • 原子性:一个事务的操作要么全部成功,要么全部失败。
  • 一致性:数据库总是从一个一致性状态到另外一个一致性的状态。
  • 隔离性:一个事务的修改在最终提交前,对其他事务都是不可见的。
  • 永久性:一旦事务提交,所做的修改都会永久保存在数据库中。

隔离性的4个隔离级别:

  • read uncommit :读未提交,可能读到其他事务没有提交的数据,叫做脏读
  • read commit: 读已提交,两次读取到的结果不一致,叫做不可重复读(同一个事务里同一个查询读取到不同的结果)。不可重复读解决脏读问题,只会读取已提交的数据,
  • read repeat: 可重复读,mysql的默认级别,每次读取的结果都一样,但是有可能产生幻读。
  • serializable:串行,一般不使用,每一行读取数据加锁,导致大量的超时和锁竞争的问题。

脏读(Drity read): 某个事务已更新一份数据,另一个事务在此时读取同一份数据,在某些原因,前一个RallBack了操作,则后一个事务所读取的数据就会是不正确的。
不可重复读(non-repeatable read):在一个事务的两次查询的数据不一致,这可能是两次查询过程中插入了一个事务更新的原来的数据。
幻读(Phantom read):在一个事务的两次查询中数据笔数不一致,例如一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前没有的。

ACID 靠什么保证?

A 原子性:有undo log 日志保证,记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql
C 一致性:由其他的三大特性来保证、程序代码要保证业务上的一致性
I 隔离性:有MVCC来保证

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

InnoDB redo log 写盘,InnoDB 事务进入prepare状态
如果前面prepare 成功,binlog 写盘,再继续将事务日志持久化到binlog,如果持久化成功,那么InnoDB 事务则进入commit状态
在redo log 里面写一个commit记录

MVCC?

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

MVCC只会在Read Commited和Repeatble read 两个隔离级别下工作,Read uncommited 总是读取最新的数据行,而不是符合当前事务版本的数据行。而Serializable 则会对所有读取的行加锁。

聚簇索引记录中有两个必要的隐藏列:

  • trx_id:用来存储每次对某条聚簇索引记录进行修改的时候的事务id
  • roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,指向这条聚簇索引记录的上一个版本的位置,通过它来获取上一个版本的记录信息。(插入操作的undo日志没有这个属性,因为没有老版本)

慢查询

原因:查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?
优化:

  1. 分析语句,看看是否load了额外的数据列,可能是查询了多余的行并且抛弃掉了,可能是加载多了许多结果中并不需要的列,对语句分析以及重写
  2. 分析语句的执行计划,然后获得其使用索引的情况 ,之后修改语句或者修改索引,是的语句可以尽可能的命中索引。
  3. 考虑数据量是否太大,进行横向或者纵向的分表。
     

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐