目录
8、Spring AOP和AspectJ AOP有什么区别?
6、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
7、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
9、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
2 Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
4 如何在Spring Boot启动的时候运行一些特定的代码
9、Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
10、如何集成 Spring Boot 和 ActiveMQ?
2.我们为什么用Redis/Redis解决了什么问题/怎样使用Redis
25.Redis的操作之所以是原子性的,是因为Redis是单线程的。
2. 核心: provider消息生产者 consumer消息消费者
1.什么是spring
2.Spring框架的好处
3、 Autowired和Resource关键字的区别?
4、依赖注入的方式有几种,各是什么?
说说你对Spring MVC的理解
5、什么是MVC模式
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器
拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
组件说明
DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低
组件之间的耦合性,提高每个组件的扩展性。
HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口
方式,注解方式等。
HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。
ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、 excel等。
6、 SpringMVC常用的注解有哪些?
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中
的所有响应请求的方法都是以该地址作为父路径。
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
7、 谈谈你对Spring的AOP理解
AOP(Aspect-Oriented Programming,面向切面编程)能够将那些与业务无关,却为业务模块所
共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复
代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。
Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用JDK
动态代理去创建代理对象;而对于没有实现接口的对象,就无法使用JDK动态代理,转而使CGlib
动态代理生成一个被代理对象的子类来作为代理。
当然也可以使用AspectJ,Spring AOP中已经集成了AspectJ,AspectJ应该算得上是Java生态系统中
最完整的AOP框架了。使用AOP之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使
用即可,这样可以大大简化代码量。我们需要增加新功能也方便,提高了系统的扩展性。日志功
能、事务管理和权限管理等场景都用到了AOP。
8、Spring AOP和AspectJ AOP有什么区别?
Spring AOP是属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理(Proxying),而
AspectJ基于字节码操作(Bytecode Manipulation)。
Spring AOP已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架了。
AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单。
如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择AspectJ,它比
SpringAOP快很多。
在Spring AOP 中,关注点和横切关注的区别是什么?
关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。 横切关
注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数
据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。
那什么是连接点呢?连接点代表一个应用程序的某个位置,在这个位置我们可以插入一个AOP切
面,它实际上是个应用程序执行Spring AOP的位置。
切入点是什么?切入点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方
式指明切入点
9、说说你对Spring的IOC是怎么理解的?
(1)IOC就是控制反转,是指创建对象的控制权的转移。以前创建对象的主动权和时机是由自己把
控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之
间的依赖关系。对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个
概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。
(2)最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反
射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。
(3)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
10、解释一下spring bean的生命周期
首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;
Spring上下文中的Bean生命周期也类似,如下:
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注
入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容
器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以 及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String
beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传
递的是Spring工厂自身。
③如果这个Bean已经实现了ApplicationContextAware接口,会调用
setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor:
如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会
调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean 与 init-method:
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(6)如果这个Bean实现了BeanPostProcessor接口,将会调用
postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调
用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(7)DisposableBean: 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(8)destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方
法。
11、解释Spring支持的几种bean的作用域?
Spring容器中的bean可以分为5个范围:
(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维
护。
(2)prototype:为每一个bean请求提供一个实例。
(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回
收。
(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,
bean会随之失效。
(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet
容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那
么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
12、Spring框架中都用到了哪些设计模式?
这是一道相对有难度的题目,你不仅要回设计模式,还要知道每个设计模式在Spring中是如何使用
的。
简单工厂模式:Spring 中的 BeanFactory 就是简单工厂模式的体现。根据传入一个唯一的标识来获得 Bean 对象,但是在传入参数后创建还是传入参数前创建,要根据具体情况来定。
工厂模式:Spring 中的 FactoryBean 就是典型的工厂方法模式,实现了 FactoryBean 接口的 bean
是一类叫做 factory 的 bean。其特点是,spring 在使用 getBean() 调用获得该 bean 时,会自动调
用该 bean 的 getObject() 方法,所以返回的不是 factory 这个 bean,而是这个 bean.getOjbect()
方法的返回值。
单例模式:在 spring 中用到的单例模式有: scope="singleton" ,注册式单例模式,bean 存放于
Map 中。bean 的 name 当做 key,bean 当做 value。
原型模式:在 spring 中用到的原型模式有: scope="prototype" ,每次获取的是通过克隆生成的新
实例,对其进行修改时对原有实例对象不造成任何影响。
迭代器模式:在 Spring 中有个 CompositeIterator 实现了 Iterator,Iterable 接口和 Iterator 接
口,这两个都是迭代相关的接口。可以这么认为,实现了 Iterable 接口,则表示某个对象是可被迭
代的。Iterator 接口相当于是一个迭代器,实现了 Iterator 接口,等于具体定义了这个可被迭代的
对象时如何进行迭代的。
代理模式:Spring 中经典的 AOP,就是使用动态代理实现的,分 JDK 和 CGlib 动态代理。
适配器模式:Spring 中的 AOP 中 AdvisorAdapter 类,它有三个实现:
MethodBeforAdviceAdapter、AfterReturnningAdviceAdapter、ThrowsAdviceAdapter。Spring
会根据不同的 AOP 配置来使用对应的 Advice,与策略模式不同的是,一个方法可以同时拥有多个
Advice。Spring 存在很多以 Adapter 结尾的,大多数都是适配器模式。
观察者模式:Spring 中的 Event 和 Listener。spring 事件:ApplicationEvent,该抽象类继承了
EventObject 类,JDK 建议所有的事件都应该继承自 EventObject。spring 事件监听器:
ApplicationListener,该接口继承了 EventListener 接口,JDK 建议所有的事件监听器都应该继承
EventListener。
模板模式:Spring 中的 org.springframework.jdbc.core.JdbcTemplate 就是非常经典的模板模式
的应用,里面的 execute 方法,把整个算法步骤都定义好了。
责任链模式:DispatcherServlet 中的 doDispatch() 方法中获取与请求匹配的处理器
HandlerExecutionChain,this.getHandler() 方法的处理使用到了责任链模式。
注意:这里只是列举了部分设计模式,其实里面用到了还有享元模式、建造者模式等。可选择性的
回答,主要是怕你回答了迭代器模式,然后继续问你,结果你一问三不知,那就尴了尬了。
13、spring循环依赖问题
什么时循环依赖问题
1. 比如说 A 完成初始化第一步并将自己提前曝光出来(通过 ObjectFactory 将自己提前曝光),在
初始化的时候,发现自己依赖对象 B,此时就会去尝试 get(B),这个时候发现 B 还没有被创建
出来;
2. 然后 B 就走创建流程,在 B 初始化的时候,同样发现自己依赖 C,C 也没有被创建出来;
3. 这个时候 C 又开始初始化进程,但是在初始化的过程中发现自己依赖 A,于是尝试 get(A)。这
个时候由于 A 已经添加至缓存中(一般都是添加至三级缓存 singletonFactories),通过
ObjectFactory 提前曝光,所以可以通过 ObjectFactory#getObject() 方法来拿到 A 对象。C 拿 到 A 对象后顺利完成初始化,然后将自己添加到一级缓存中;
4. 回到 B,B 也可以拿到 C 对象,完成初始化,A 可以顺利拿到 B 完成初始化。到这里整个链路
就已经完成了初始化过程了。
Spring事务定义了7种传播机制:
1. PROPAGATION_REQUIRED:默认的Spring事物传播级别,若当前存在事务,则加入该事务,若不存在事务,则新建一个事务。
2. PAOPAGATION_REQUIRE_NEW:若当前没有事务,则新建一个事务。若当前存在事务,则新建一个事务,新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交。
3. PROPAGATION_NESTED:如果当前存在事务,则嵌套在当前事务中执行。如果当前没有事务,则新建一个事务,类似于REQUIRE_NEW。 4. PROPAGATION_SUPPORTS:支持当前事务,若当前不存在事务,以非事务的方式执行。
5. PROPAGATION_NOT_SUPPORTED:以非事务的方式执行,若当前存在事务,则把当前事务挂
起。
6. PROPAGATION_MANDATORY:强制事务执行,若当前不存在事务,则抛出异常.
7. PROPAGATION_NEVER:以非事务的方式执行,如果当前存在事务,则抛出异常。
Spring事务传播级别一般不需要定义,默认就是PROPAGATION_REQUIRED,除非在嵌套事务的情况下需要重点了解。
14、Spring 事务实现方式
编程式事务管理:这意味着你可以通过编程的方式管理事务,这种方式带来了很大的灵活性,但很
难维护。
声明式事务管理:这种方式意味着你可以将事务管理和业务代码分离。你只需要通过注解或者XML
配置管理事务。
Spring框架的事务管理有哪些优点
它为不同的事务API(如JTA, JDBC, Hibernate, JPA, 和JDO)提供了统一的编程模型。它为编程式事务管理提供了一个简单的API而非一系列复杂的事务API(如JTA).它支持声明式事务管理。它可以和
Spring 的多种数据访问技术很好的融合。
在xml中设置
1/事务的传播行为 2/事务的隔离级别 3/获得事务信息
14、事务三要素是什么?
数据源:表示具体的事务性资源,是事务的真正处理者,如MySQL等。
事务管理器:像一个大管家,从整体上管理事务的处理过程,如打开、提交、回滚等。
事务应用和属性配置:像一个标识符,表明哪些方法要参与事务,如何参与事务,以及一些相关属
性如隔离级别、超时时间等。
15、事务注解的本质是什么?
@Transactional 这个注解仅仅是一些(和事务相关的)元数据,在运行时被事务基础设施读取消
费,并使用这些元数据来配置bean的事务行为。 大致来说具有两方面功能,一是表明该方法要参
与事务,二是配置相关属性来定制事务的参与方式和运行行为
声明式事务主要是得益于Spring AOP。使用一个事务拦截器,在方法调用的前后/周围进行事务性
增强(advice),来驱动事务完成。
@Transactional注解既可以标注在类上,也可以标注在方法上。当在类上时,默认应用到类里的所
有方法。如果此时方法上也标注了,则方法上的优先级高。 另外注意方法一定要是public的。
读未提交(Read uncommitted),一个事务可以读取另一个未提交事务的数据,最低级别,任何情况都无法保证。
(1)所有事务都可以看到其他未提交事务的执行结果
(2)本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少
(3)该级别引发的问题是——脏读(Dirty Read):读取到了未提交的数据
读已提交(Read committed),一个事务要等另一个事务提交后才能读取数据,可避免脏读的发生。
(1)这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)
(2)它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变
(3)这种隔离级别出现的问题是——不可重复读(Nonrepeatable Read):不可重复读意味着我们在同一个事务中执行完全相同的select语句时可能看到不一样的结果。
|——>导致这种情况的原因可能有:(1)有一个交叉的事务有新的commit,导致了数据的改变;(2)一个数据库被多个实例操作时,同一事务的其他实例在该实例处理其间可能会有新的commit
可重复读(Repeatable read),就是在开始读取数据(事务开启)时,不再允许修改操作,可避免脏读、不可重复读的发生。
(1)这是MySQL的默认事务隔离级别
(2)它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行
(3)此级别可能出现的问题——幻读(Phantom Read):当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行
(4)InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题
串行(Serializable),是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。Mysql的默认隔离级别是Repeatable read。
(1)这是最高的隔离级别
(2)它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。
(3)在这个级别,可能导致大量的超时现象和锁竞争
MyBatis
1、什么是MyBatis
(1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL
语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直
接编写原生态sql,可以严格控制sql执行性能,灵活度高。
(2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避
免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
(3)通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和
statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果
映射为java对象并返回。(从执行sql到返回result的过程)。
2、说说MyBatis的优点和缺点
优点:
(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写 在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连
接;
(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
(4)能够与Spring很好的集成;
(5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象
关系组件维护。
缺点:
(1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
3、#{}和${}的区别是什么?
#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
4、当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
第2种: 通过来映射字段名和实体类属性名的一一对应的关系。
5、Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分
页。可以在sql内直接拼写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页,比如:MySQL数据的时候,在原有SQL后面拼写limit。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截
待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
6、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
第一种是使用标签,逐一定义数据库列名和对象属性名之间的映射关系。
第二种是使用sql列的别名功能,将列的别名书写为对象属性名。
有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋
值并返回,那些找不到映射关系的属性,是无法完成赋值的。
7、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
加上动态sql的9个标签,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策
略标签。
8、MyBatis实现一对一有几种方式?具体怎么操作的?
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在resultMap里面配置
association节点配置一对一的类就可以完成;
嵌套查询是先查一个表,根据这个表里面的结果的 外键id,去再另外一个表里面查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。
9、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一
对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调
用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。
10、说说Mybatis的缓存机制
在应用运行过程中,我们有可能在一次数据库会话中,执行多次查询条件完全相同的 SQL,
MyBatis 提供了一级缓存的方案优化这部分场景,如果是相同的 SQL 语句,会优先命中一级缓存,避免直接对数据库进行查询,提高性能。二级缓存开启后,同一个 namespace 下的所有操作语句,都影响着同一个 Cache,即二级缓存被多个 SqlSession 共享,是一个全局的变量。
二级缓存 -> 一级缓存 -> 数据库
1. MyBatis 的二级缓存相对于一级缓存来说,实现了 SqlSession 之间缓存数据的共享,同时粒度
更加细,能够到 namespace 级别,通过 Cache 接口实现类不同的组合,对 Cache 的可控性
也更强。
2. MyBatis 在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件
比较苛刻。
3. 在分布式环境下,由于默认的 MyBatis Cache 实现都是基于本地的,分布式环境下必然会出现
读取到脏数据,需要使用集中式缓存将 MyBatis 的 Cache 接口实现,有一定的开发成本,直
接使用 Redis、Memcached 等分布式缓存可能成本更低,安全性也更高。
11、MyBatis 中见过什么设计模式?
Builder模式 :
例如 SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;
工厂模式 :例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
单例模式 :例如ErrorContext和LogFactory;
代理模式 :Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
组合模式 :例如SqlNode和各个子类ChooseSqlNode等;
模板方法模式 : 例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
适配器模式 : 例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
装饰者模式 : 例如cache包中的cache.decorators子包中等各个装饰者的实现;
迭代器模式 : 例如迭代器模式PropertyTokenizer;
14、MyBatis 中比如 UserMapper.java 是接口,为什么没有实现类还能调用?
使用JDK动态代理+MapperProxy。本质上调用的是MapperProxy的invoke方法。
SpringBoot
1、为什么要用SpringBoot
Spring Boot 优点非常多,如:一、独立运行Spring Boot而且内嵌了各种servlet容器,Tomcat、Jetty等,现在不再需要打成war包部署到容器中,Spring Boot只要打成一个可执行的jar包就能独立运行,所有的依赖包都在一个jar包内。
二、简化配置spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置。
三、自动配置Spring Boot能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starter-web启动器就能拥有web的功能,无需其他配置。
四、无代码生成和XML配置Spring Boot配置过程中无代码生成,也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的,这也是Spring4.x的核心功能之一。
五、应用监控Spring Boot提供一系列端点可以监控服务及应用,做健康检测。
2 Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了
以下 3 个注解:
@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数
据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class
})。
@ComponentScan:Spring组件扫描。
3、运行Spring Boot有哪几种方式?
1)打包用命令或者放到容器中运行
2)用 Maven/Gradle 插件运行
3)直接执行 main 方法运行
4 如何在Spring Boot启动的时候运行一些特定的代码
如果你想在Spring Boot启动的时候运行一些特定的代码,你可以实现接口ApplicationRunner或者CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法。
CommandLineRunner:启动获取命令行参数
5、Spring Boot中的监视器是什么?
Spring boot actuator是spring启动框架中的重要功能之一。Spring boot监视器可帮助您访问生产环境中正在运行的应用程序的当前状态。
有几个指标必须在生产环境中进行检查和监控。即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息。监视器模块公开了一组可直接作为HTTP URL访问的REST端点来检查状态
6、如何使用Spring Boot实现异常处理
Spring提供了一种使用ControllerAdvice处理异常的非常有用的方法。我们通过实现一个ControlerAdvice类,来处理控制器类抛出的所有异常。
7、springboot常用的starter有哪些
spring-boot-starter-web 嵌入tomcat和web开发需要servlet与jsp支持
spring-boot-starter-data-jpa 数据库支持
spring-boot-starter-data-redis redis数据库支持
spring-boot-starter-data-solr solr支持
mybatis-spring-boot-starter 第三方的mybatis集成starter
8、如何理解 Spring Boot 配置加载顺序?
在 Spring Boot 里面,可以使用以下几种方式来加载配置。
1)properties文件;
2)YAML文件;
3)系统环境变量;
4)命令行参数;
9、Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
pring Boot 的核心配置文件是 application 和 bootstrap 配置文件。application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有以下几个应用场景:
使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
一些固定的不能被覆盖的属性;
一些加密/解密的场景;
10、如何集成 Spring Boot 和 ActiveMQ?
对于集成 Spring Boot 和 ActiveMQ,我们使用 spring-boot-starter-activemq 依赖关系。它只需要很少的配置,并且不需要样板代码。
redis
1.Redis是什么
Redis是一个开源的,基于内存的,支持多种数据结构的存储系统,可以作为数据库/缓存/消息中间件使用
2.我们为什么用Redis/Redis解决了什么问题/怎样使用Redis
提高应用的读写能力,实际中主要是提高读的能力,带来更高的并发.
Redis读写性能比 Mysql 好的多,我们就可以把 Mysql 中的热点数据缓存到 Redis 中,
提升读取性能,同时也减轻了 Mysql 的读取压力
3.Redis的优点以及原因
读取速度快,因为数据存在内存中,所以数据获取快;
支持多种数据结构,包括字符串、列表、集合、有序集合、哈希等;
支持事务,且操作遵守原子性,即对数据的操作要么都执行,要么都不执行;
还拥有其他丰富的功能,队列、主从复制、集群、数据持久化等功能。
4.Redis怎么保证高可用
Redis利用哨兵和集群保证高可用,内置了复制(Replication)、LUA 脚本(Lua scripting)、LRU 驱动事件(LRU eviction)、事务(Transactions)和不同级别的磁盘持久化(persistence)功能
5.为什么 Redis 单线程模型效率也能那么高?
1. C语言实现,效率高
2. 纯内存操作
3. 基于非阻塞的IO复用模型机制
4. 单线程的话就能避免多线程的频繁上下文切换问题
5. 丰富的数据结构(全称采用hash结构,读取速度非常快,对数据存储进行了一些优化,比如亚
索表,跳表等)
6.Redis 的线程模型
Redis 内部使用文件事件处理器 file event handler ,
这个文件事件处理器是单线程的,所以Redis 才叫做单线程的模型
7.Redis 的同步机制
Redis 支持主从同步、从从同步。如果是第一次进行主从同步,主节点需要使用 bgsave 命令,再将
后续修改操作记录到内存的缓冲区,等 RDB 文件全部同步到复制节点,复制节点接受完成后将
RDB 镜像记载到内存中。等加载完成后,复制节点通知主节点将复制期间修改的操作记录(AOF)同步到复
制节点,即可完成同步过程。
8. pipeline(管道)
pipeline(管道)的好处在于可以将多次 I/O 往返的时间缩短为一次,但是要求管道中执行的指令间没有因果关系
9.redis的优点
速度快: 查找和操作的时间复杂度都是O (1)
数据结构丰富: 支持 String ,List,Set,Sorted Set,Hash 五种基础的数据结构
持久化储存: Redis 提供 RDB 和 AOF 两种数据的持久化存储方案,解决内存数据库最担心的万一 Redis 挂掉,数据会消失掉
丰富的特性: Key过期、计数、分布式锁、消息队列等。
10.redis的缺点
储存数据量和机器本身内存大小有关,需要定期删除数据
如果进行完整重同步,需要生成RDB文件,并进行传输,会占用主机CPU,并消耗现网的带宽(完整重同步(RDB),部分重同步(AOF))
修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程中, Redis不能提供服务。
11.redisTemplate常用api
redisTemplate.opsForValue();//操作字符串 set("k","v")添加值 get("key")获取值 setIfAbsent("multi1","multi1"))添加值并返回是否存在
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set
Redis数据结构以及命令
String 常用指令
incr/incrby键递增/递减 incr/incrby减少指定的整数 append向尾部追加值
strlen返回数据的长度 mset/mget同时设置/获取多个键值
博客的字数统计如何实现?(strlen)
如何将审计日志不断追加到指定key?(append)
你如何实现一个分布式自增id?(incr-雪花算法)
如何实现一个博客的的点赞操作?(incr,decr)
一般做一些复杂的计数功能的缓存
Hash类型应用实践
hset/hget赋值和取值 hmset/hmget设置和获取对象属性 hexists属性是否存在
hdel删除属性 hkeys/hvals只获取字段名HKEYS或字段值HVALS
发布一篇博客需要写内存吗?(需要,hmset)
浏览博客内容会怎么做?(hmget)
如何判定一篇博客是否存在?(hexists)
删除一篇博客如何实现?(hdel)
分布式系统中你登录成功以后是如何存储用户信息的?(hmset)
List类型应用实践
lpush/rpush list的头部/尾部添加字符串元素 del清空集合元素 linsertkey对应list的特定位置之前或之后
lset 通过下标获取值 lrem 从key对应list中删除X个和value相同的元素
ltrim 保留指定key 的值范围内的数据 lpop/rpop 从list的头部/尾部删除()弹出元素,并返回删除元素
llen 返回key对应list的长度 lindex 返回名字为key的list中index位置的元素
rpoplpush 从第一个list的尾部移除元素并添加到第二个list的头部,返回元素.原子性操作,如果为空返回nil:
如何基于redis实现一个队列结构?(lpush/rpop)
如何基于redis实现一个栈结构?(lpush/lpop)
如何基于redis实现一个阻塞式队列?(lpush/brpop)
如何实现秒杀活动的公平性?(先进先出-FIFO)
通过list结构实现一个消息队列(顺序)吗?(可以,FIFO->lpush,rpop)
用户注册时的邮件发送功能如何提高其效率?(邮件发送是要调用三方服务,底层通过队列优化其效率,队列一般是list结构)
如何动态更新商品的销量列表?(卖的好的排名靠前一些,linsert)
商家的粉丝列表使用什么结构实现呢?(list结构)
Set类型应用实践
sadd 添加元素,重复元素添加失败,返回0 smembers获取集合中成员 spop移除并返回集合中的一个随机元素
scard 获取集合中的成员个数 smove移动一个元素到另外一个集合 sunion实现集合的并集操作
srem 删除指定元素
朋友圈的点赞功能你如何实现?(sadd,srem,smembers,scard)
如何实现一个网站投票统计程序?
你知道微博中的关注如何实现吗?
Sorted Set
Sorted Set 多了一个权重参数 Score,集合中的元素能够按 Score 进行排列。
可以做排行榜应用,取 TOP(N) 操作。Sorted Set 可以用来做延时任务
12.1Redis刷新策略
LRU/LFU/FIFO算法剔除(最少使用,最久没用,先进先出),当Redis内存达到最大,删除过期数据,保护内存.
超时剔除,设置过期时间
主动更新,开发控制生命周期
12.2Redis删除策略
定期删除,而不是定时删除.第一步redis默认每个100ms检查一批key,第二步过期就删除,如果过期的key占比高就重复第一步.
惰性删除,key被使用的时候判断是否过期,如果过期就删除
主动删除,配置maxmemory-policy的淘汰策略
13.redis持久化方式有哪些?以及有什么区别?
redis提供两种持久化机制RDB和AOF机制:
RDB持久化方式:
是指用数据集快照的方式办持久化模式记录redis数据库的所有键值对,再某个时间点将数据写入一个
临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复.
优点:
只有一个文件dump.rdb,方便持久化.
容灾性好,一个文件可以保存到安全的磁盘.
性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以是IO最大化.使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了Redis的高性能
相对于数据集大时,比AOP的启动效率高
缺点:
数据安全性低.RDB时间隔一段时间进行持久化,如果持久化之间Redis发生故障,会发生数据丢失.所以这种方式更适合数据要求不严谨的时候
AOP持久化方式(Append-only file)
是指所有的命令行记录以 Redis 命令请求协议的格式完全持久化存储,保存为 AOF 文件。
优点:
(1)数据安全, AOF 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录到 AOF 文件中一次。
(2)通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof 工具解决数据一致性问题。
(3) AOF 机制的 rewrite 模式。 AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall )
缺点:
(1) AOF 文件比 RDB 文件大,且恢复速度慢。
(2)数据集大的时候,比 RDB 启动效率低
14,怎么使用 Redis 实现消息队列
使用 list 结构作为队列, rpush 生产消息, lpop 消费消息。当 lpop 没有消息的时候,要适当sleep 一会再重试
15, Redis为什么设计成单线程的
多线程处理的话涉及到锁,并且多线程处理会涉及到线程切换消耗CPU,采用单线程避免不必要的上下文切换和竞争条件.其次
CPU不是Redis的瓶颈,Redis的瓶颈可能是内存和带宽
16.数据库崩溃,系统出现 502 问题
17.Redis出现的问题:
1.key冲突 按业务名和参数区分开 进行取名
2.报内存不足
2.1修改配置文件 redis.conf 的 maxmemory 参数,增加 Redis 可用内存
2.2设置缓存淘汰策略,提高内存的使用效率
2.3使用 Redis 集群模式,提高存储量
18.redis集群(Redis Cluster)的原理
所有的节点相互连接
集群消息通信通过集群总线通信,集群总线端口大小为客户端服务端口 + 10000(固定值)
节点与节点之间通过二进制协议进行通信
客户端和集群节点之间通信和通常一样,通过文本协议进行
集群节点不会代理查询
数据按照 Slot 存储分布在多个 Redis 实例上
集群节点挂掉会自动故障转移
可以相对平滑扩/缩容节点
19.集群架构模式有几种
Redis 集群架构是支持单节点单机模式的,也支持一主多从的主从结构,还支持带有哨兵的集群部署模式
20.怎么提高缓存命中率
提前加载数据到缓存中;
增加缓存的存储空间,提高缓存的数据;
调整缓存的存储数据类型;
提升缓存的更新频率
21.怎么解决缓存和数据库不一致
21.1不一致,主要是并发写请求还没执行完读请求就过来,将写请求放到缓存队列,开始执行写请求的具体操作
(删除缓存/更新数据库/更新缓存)
21.2 分三种情况 直接返回/删除完缓存之后更新失败写请求返回/更新完数据库后更新缓存失败/更新缓存成功
读取缓存旧值/读取数据库旧值,把旧值写到缓存 /读取数据库新值,把新值写入数据库/读取缓存新值
20.你们公司怎么做Redis持久化
1.保障性能,Master不做任何持久化工作
2.一个Slave开启AOF备份数据,策略为每秒同步一次
3.最好Masterhe和Slave再同一个局域网
4.尽量避免再压力大的主库上增加从库
23,Redis 常见性能问题和解决方案有哪些?
Master 最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件;
如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次;
为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网内;
尽量避免在压力很大的主库上增加从库;
主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <-
Slave3….;这样的结构方便解决单点故障问题,实现 Slave 对 Master 的替换。如果 Master 挂
了,可以立刻启用 Slave1 做 Master,其他不变。
24.热点数据和冷数据
只有热点数据才有缓存的价值,冷数据即时缓存可能等不到下次被访问就被挤出内存.比如常见日用品就是热点数据.
25.Redis的操作之所以是原子性的,是因为Redis是单线程的。
26.Redis为什么设置为单线程:
基于内存操作本身就快速,cpu一般不会成为瓶颈,没必要多线程,不用上下文切换和线程竞争机制,反而保证速度
27.如何解决redis的并发竞争key问题
(1)如果对这个key操作,不要求顺序方案为
准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可
(2)如果对这个key操作,要求顺序,方案为
分布式锁+时间戳。 假设一个系统抢到锁,再key后面加一个时间,接下来抢到锁的发现自己的时间戳早于缓存中的时间戳,那就不做set操作.
(3) 利用队列,将set方法变成串行访问也可以redis遇到高并发,如果保证读写key的一致性 对redis的操作都是具有原子性的,是线程安全的操作,
你不用考虑并发问题,redis内部已经帮你处理好并发的问题了。
rebbitMQ
为什么用MQ/MQ解决了什么问题
异步: 分布式条件下,一个请求时间太久,有的服务不影响响应客户,可以异步处理
追问:为什么不用线程池而是用消息队列? 创建一个线程池统筹管理一个请求,耦合性太强,一旦一个服务
解耦:多个消息生产者都可以把消息放到同一个队列,多个消息消费者都可以在同一个队列里面获取消息,他们互相之间只需要考虑和队列建立联系
削峰:减少高峰期服务器的压力
用MQ有那些缺点
系统可用性降低-----系统引入的外部依赖越多,越容易挂掉。万一 MQ 挂了,MQ 一挂,整套系统崩溃
解决方案: 主备架构(备用节点) 镜像集群模式
系统复杂度提高----硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?
1.生产者丢失,用RabbitMQ 提供的事务功能,如果消息没接收到返回给生产者,回滚事务.具体:confirm模式
2.MQ中丢失,解决方案:开启RabbitMQ 的持久化:1.创建 queue 的时候将其设置为持久化,2.发送消息的时候将消息的 deliveryMode 设置为 2
3.消费端丢失:ack机制 确认机制
怎么保证消息传递的顺序性和一致性问题
RabbitMQ保证消息的顺序性解决方案:给 RabbitMQ 创建多个 queue,生产者把同一个订单号的消息发送到同一个 queue,消费者固定消费一个 queue 的消息,
RabbitMQ保证消息的一致性解决方案:两阶段或者三阶段提交协议来完成分布式事务
1.为什么选RabbitMQ来实现消息队列
1 除了Opid,RabbitsMQ是唯一实现了AMQP标准的消息服务器
2 RabbitMQ的持久化支持保证了消息的稳定性
3 用Erlang语言开发,适合高并发和高可用还有部署简单
4 社区活跃度高
2. 核心: provider消息生产者 consumer消息消费者
RabbitMQ 消息队列(存放消息的容器,就像是存放了商品的仓库/中转站)
队列可以储存很多信息,他是一个无限制的缓冲区,多个生产者可以将消息发送给同一个队列,
多个消息者也可以到一个队列里面去接收
3.MQ配置信息
配置文件 默认账号密码是 guest,设置队列名字
配置类 把队列添加到容器
4.原理
Exchange交换器 Binding绑定 Queue队列,队列对应Connection(连接)
(Exchange交换器 Binding绑定 Queue队列)属于Viitual 属于Broker
exchageType决定怎样放进队列
5.概念
Message : 消息是不具名的,它由消息头消息体组成,消息体是不透明的,而消息头则由一系列可选属性组成
Publisher: 消息生产者,也是一个向交换器发布消息的客户端应用程序
Consumer:消息的消费者,表示一个从消息队列中取得消息的客户端应用程序
Exchange:交换器 用来接收生产者发送的消息并将这些消息路由给服务器的队列
Binding:将交换器和队列连接的路由规则
Queue:队列,消息的容器
Routing-key :路由键.RabbitMQ决定消息投递到哪个队列的规则
Connection: rabbit服务器和服务建立的TCP连接
Channel: 信道,是TCP里面的虚拟连接,例如:电缆相当于TCP,信道是一个光纤束
Virtual Host:虚拟主机
Broker:表示消息队列服务器实体
三种常用的交换器类型:
1. direct(发布于订阅完全匹配)
2. fanout(广播)
3. toplc(主题,规则匹配)
feign
feign集成ribbon
负载均衡--默认开启负载均衡
重试--默认使用了重试
Ribbon:调用后台服务失败(异常,服务器奔溃,超市),可以发起重试调用
重试参数:
ribbon.MaxAutoRetries--单台服务器重试次数,默认0
ribbon.MaxAutoRetriesNextServer--更换服务器次数,默认1
ribbon.ReadTimeout--接收响应的超时时间,默认为1000ms
ribbon.ConnectTimeout-与后台服务器建立连接等待超时时间1000ms
ribbon.OkToRetryOnAllOperation-是否对所有请求重试,默认只对get重试
feign核心步骤
第一步:添加Spring-cloud-Starter-openfeign依赖
第二步: 在启动类上添加@EnableFeignClients注解 (
1 此注解和FeignClientsRegistrar类将生成的FeignClient注册到 IOC容器中,
类型是FeignClientFactoryBean,无论多少FeignClient类型都一样.
2 FeignClientFactoryBean实现了FactoryBean,我们关注FeignClientFactoryBean#getObejct方法就可以了)
----------------------如何判断@EnableFeignClients注解有没有进行依赖注入---------------------------------
创建了一个FeignClient,并没有注入到任何@Component类中,即没有任何地方会用到这个FeignClient,
然后在FeignClientFactoryBean#getObejct上加上断点,项目在启动时并没有进入断点,
可见FeignClientsRegistrar只是将FeignClientFactoryBean注册到了IOC容器,并没有做更多的工作。
------------------------------------------------------------------------------------------------------------------------------
3 依赖注入发生在controller层, controller层中@Autowired 将service层注入,而service方法上有@FeignClients注解
Linux常用指令
1 cd命令集
ifconfig/ip addr 检查IP地址
pwd 检查当前的位置
tab键 自动补齐(注意唯一性)
cd命令是linux中最基本的命令语句,必须熟练掌握
cd / 返回根目录
cd ~ 用户主目录
cd . 当前目录
cd ..返回到上一级目录
cd /usr/ 进入到usr目录
cd – 返回上一个目录
cd 直接回家
2 ls目录和文件
ls –l 详细格式,文件权限,时间
ll 和ls –l作用相同
ls *.txt 查看所有的txt类型文档
3 目录操作
mkdir 创建目录
mkdir a 创建 a目录
mkdir -p a/b 创建 a目录,并在a目录里创建b目录
mkdir -m 777 c 创建一个权限为777的C目录
rmdir 删除目录(如果目录里有文件,则不能用此命令)
4 Vi/vim创建/查看/编辑文件
命令行:Esc切换到命令行模式。
编辑模式:
按i,在光标前开始编辑
按a,在光标后开始编辑
按o,在当前行的下一行开始编辑
按u, 撤销之前的操作
底行模式:按 shift+:冒号。
:q! 不保存退出
:wq 保存退出
:/world 从当前光标处,向上查找world关键字
:?world 从当前光标处,向后查找world关键字
5 删除文件
rm 删除文件
rm n.txt 提示y删除n放弃
rm –f n.txt 不提示
rm –rf dirname 不提示递归删除目录下所以内容
rm –rf * 删除所有文件
rm –rf /* 删除所有子目录所有和文件
6 复制和移动文件
cp复制文件
cp nginx.conf n.txt
cp –R tomcat1 tomcat2 #复制整个目录
mv 修改文件名,移动文件
mv n.txt m.txt 修改文件名称
7 浏览文件
cat 输出文件所有的内容
more 输出文档所有的内容,分页输出,空格浏览下一屏,q退出
less 用法和more相同,只是通过PgUp、PgOn键来控制
tail 用于显示文件后几号,使用频繁
tail -10 nginx.conf 查看nginx.conf的最后10行
tail –f nginx.conf 动态查看日志,方便查看日志新增的信息
ctrl+c 结束查看
8 打包命令
tar命令位于/bin目录下,它能够将用户所指定的文件或目录打包成一个文件,但不做压缩。一般Linux上常用的压缩方式是选用tar将许多文件打包成一个文件,再以gzip压缩命令压缩成name.tar.gz的文件。
-c 创建一个新的tar文件
-v 显示运行过程的信息
-f 指定文件名
-z 调用gzip压缩命令进行压缩
-t 查看压缩文件的内容
-x 解开tar文件
tar –cvf n.tar ./* 压缩当前目录下的所有文件和目录,文件名为n.tar
tar –xvf n.tar 解压压缩包中的文件到当前目录(如果长时间未解压成功 Ctrl+C推出)
tar –cvzf m.tar.gz ./* 压缩文件
tar -zxvf m.tar.gz 解压m.tar文件到当前目录
9 grep命令
grep root /etc/passwd 在文件中查找关键字root
grep root /etc/passwd –-color 高亮显示
grep root /etc/passwd –A5 –B5 高亮显示,A后5行,B前5行
grep -n root /etc/passwd 查找并显示行数
grep -v root /etc/passwd 取反,查出不含root的数据
数据库
1 数据库隔离级别
读未提交(Read uncommitted),一个事务可以读取另一个未提交事务的数据,最低级别,任何情况都无法保证。
(1)所有事务都可以看到其他未提交事务的执行结果
(2)本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少
(3)该级别引发的问题是——脏读(Dirty Read):读取到了未提交的数据
读已提交(Read committed),一个事务要等另一个事务提交后才能读取数据,可避免脏读的发生。
(1)这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)
(2)它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变
(3)这种隔离级别出现的问题是——不可重复读(Nonrepeatable Read):不可重复读意味着我们在同一个事务中执行完全相同的select语句时可能看到不一样的结果。
|——>导致这种情况的原因可能有:(1)有一个交叉的事务有新的commit,导致了数据的改变;(2)一个数据库被多个实例操作时,同一事务的其他实例在该实例处理其间可能会有新的commit
可重复读(Repeatable read),就是在开始读取数据(事务开启)时,不再允许修改操作,可避免脏读、不可重复读的发生。
(1)这是MySQL的默认事务隔离级别
(2)它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行
(3)此级别可能出现的问题——幻读(Phantom Read):当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行
(4)InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题
串行(Serializable),是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。Mysql的默认隔离级别是Repeatable read。
(1)这是最高的隔离级别
(2)它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。
(3)在这个级别,可能导致大量的超时现象和锁竞争