目录
BeanFactory 和 ApplicationContext有什么区别?
什么是Spring的依赖注入(Dependency Injection)?
Spring AOP and AspectJ AOP 有什么区别?AOP 有哪些实现方式?
使用@Autowired注解自动装配bean的过程是怎样的?
@Component, @Controller, @Service, @Repository有何区别?
Spring支持的事务管理类型, Spring事务实现方式有哪些?你更倾向用哪种事务管理类型?
Spring概述
什么是Spring?
Spring是一个轻量级Java开源框架,最早由Rod Johnson创建,目的是解决企业级应用开发的复杂性,简化Java开发。Spring为开发Java应用程序提供全面的基础架构支持,因此Java开发者可以专注于应用程序的开发。
Spring可以做很多事情,它为企业级开发提供给了丰富的功能,但是这些功能的底层都依赖于它的两个核心特性,也就是依赖注入(dependency injection,DI)和面向切面编程(aspect-oriented programming,AOP)。
为了降低Java开发的复杂性,Spring采取了以下4种关键策略
-
基于POJO的轻量级和最小侵入性编程;
-
通过依赖注入和面向接口实现松耦合;
-
基于切面和惯例进行声明式编程;
-
通过切面和模板减少样板式代码。
Spring框架的设计目标,设计理念,和核心是什么?
Spring设计目标:Spring为开发者提供一个一站式轻量级应用开发平台;
Spring设计理念:在JavaEE开发中,支持POJO和JavaBean开发方式,使应用面向接口开发,充分支持OO(面向对象)设计方法;Spring通过IoC容器实现对象耦合关系的管理,并实现依赖反转,将对象之间的依赖关系交给IoC容器,实现解耦;
Spring框架的核心:IoC容器和AOP模块。通过IoC容器管理POJO对象以及他们之间的耦合关系;通过AOP以动态非侵入的方式增强服务,把遍布于应用各层的功能分离出来形成可重用的功能组件。
Spring的优缺点是什么?
优点
-
方便解耦,简化开发
Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护,交给Spring管理。
-
AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
-
声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程。
-
方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序。
-
方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。
-
降低JavaEE API的使用难度
Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
缺点
-
Spring明明一个很轻量级的框架,却给人感觉大而全
-
Spring依赖反射,反射影响性能
-
使用门槛升高,入门Spring需要较长时间
Spring有哪些应用场景?
应用场景:JavaEE企业应用开发,包括SSH、SSM等
Spring价值:
-
Spring是非侵入式的框架,目标是使应用程序代码对框架依赖最小化;
-
Spring提供一个一致的编程模型,使应用直接使用POJO开发,与运行环境隔离开来;
-
Spring推动应用设计风格向面向对象和面向接口开发转变,提高了代码的重用性和可测试性;
Spring由哪些模块组成?
Spring 总共大约有 20 个模块, 由 1300 多个不同的文件构成。而这些组件被分别整合在核心容器(Core Container)
、 AOP(Aspect Oriented Programming)和设备支持(Instrumentation)
、数据访问与集成(Data Access/Integration)
、 Web
、 消息(Messaging)
、 Test
等 6 个模块中。以下是 Spring 5 的模块结构图:
-
spring core:提供了框架的基本组成部分,包括控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)功能。
-
spring beans:提供了BeanFactory,是工厂模式的一个经典实现,Spring将管理对象称为Bean。
-
spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
-
spring jdbc:提供了一个JDBC的抽象层,消除了烦琐的JDBC编码和数据库厂商特有的错误代码解析, 用于简化JDBC。
-
spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
-
spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
-
spring test:主要为测试提供支持的,支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。
Spring 框架中都用到了哪些设计模式?
-
工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
-
单例模式:Bean默认为单例模式。
-
代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
-
模板方法:用来解决代码重复的问题。比如:RestTemplate, JmsTemplate, JpaTemplate。
-
观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被动更新,如Spring中listener的实现--ApplicationListener。
控制反转(IOC)
什么是Spring IOC 容器?
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对对象组件控制权的转移,从程序代码本身转移到了外部容器。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。)
控制反转(IoC)有什么作用?
-
管理对象的创建和依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序猿来维护的话,那是相当头疼的
-
解耦,由容器去维护具体的对象
-
托管了类的整个生命周期,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的
Spring IoC 的实现机制
Spring 中的 IoC 的实现原理就是工厂模式加反射机制。
示例:
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
f=(Fruit)Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("com.jourwon.spring.Apple");
if(f!=null){
f.eat();
}
}
}
BeanFactory 和 ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
为了更直观的展示 “低级容器” 和 “高级容器” 的关系,这里通过常用的 ClassPathXmlApplicationContext 类来展示整个容器的层级 UML 关系。
依赖关系
BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。我们可以称之为 “低级容器”。
ApplicationContext接口作为BeanFactory的派生,可以称之为 “高级容器”。除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
-
继承MessageSource,因此支持国际化。
-
统一的资源文件访问方式。
-
提供在监听器中注册bean的事件。
-
同时加载多个配置文件。
-
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
加载方式
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
创建方式
BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
注册方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
什么是Spring的依赖注入(Dependency Injection)?
控制反转IoC是一个很大的概念,可以有不同的实现方式。其主要实现方式有两种:依赖注入和依赖查找
依赖注入:相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入(Dependency Injection),即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。组件不做定位查询,只提供普通的Java方法,让容器去决定依赖关系。
依赖查找(Dependency Lookup):容器提供回调接口和上下文环境给组件。EJB和Apache Avalon都使用这种方式。
依赖查找也有两种类型:依赖拖拽(DP)和上下文依赖查找(CDL)。
有哪些不同类型的依赖注入实现方式?
依赖注入是时下最流行的IoC实现方式,依赖注入分为接口注入(Interface Injection),Setter方法注入(Setter Injection)和构造器注入(Constructor Injection)三种方式。其中接口注入由于在灵活性和易用性比较差,现在从Spring4开始已被废弃。
构造器注入:构造器注入是容器通过调用一个类的构造器来实现的,该构造器有一系列参数,每个参数都必须注入。
Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法来实现的依赖注入。
构造器注入和 Setter方法注入的区别?
构造器注入 | setter 注入 | |
部分注入 | 没有部分注入 | 有部分注入 |
覆盖setter属性 | 不会覆盖 setter 属性 | 会覆盖 setter 属性 |
任意修改是否创建新实例 | 任意修改都会创建一个新实例 | 任意修改不会创建一个新实例 |
适用场景 | 适用于设置很多属性 | 适用于设置少量属性 |
最好的解决方案是用构造器参数实现强制依赖,setter方法实现可选依赖。
面向切面编程(AOP)
什么是AOP?
OOP(Object-Oriented Programming)面向对象编程,允许开发者定义纵向的关系,但并不适用于定义横向的关系,导致了大量重复代码,而不利于各个模块的重用。
AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),通过面向切面编程减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。常用于权限认证、日志、事务处理等。
Spring AOP and AspectJ AOP 有什么区别?AOP 有哪些实现方式?
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
JDK动态代理和CGLIB动态代理的区别?
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
-
JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
-
如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。
解释一下Spring AOP里面的几个名词
(1)切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了切面的全部内容。在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。
(2)连接点(Join point):指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。应用可能有数以千计的时机应用通知。这些时机被称为连接点。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
(3)通知(Advice):在AOP术语中,切面的工作被称为通知。
(4)切入点(Pointcut):切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。
(5)引入(Introduction):引入允许我们向现有类添加新方法或属性。
(6)目标对象(Target Object):被一个或者多个切面(aspect)所通知(advise)的对象。它通常是一个代理对象。也有人把它叫做 被通知(adviced) 对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
(7)织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。在目标对象的生命周期里有多少个点可以进行织入:
-
编译期:切面在目标类编译时被织入。AspectJ的织入编译器是以这种方式织入切面的。
-
类加载期:切面在目标类加载到JVM时被织入。需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入就支持以这种方式织入切面。
-
运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面。
Spring通知有哪些类型?
在AOP术语中,切面的工作被称为通知,实际上是程序执行时要通过SpringAOP框架触发的代码段。
以下是Spring定义的五种通知和常见使用场景
通知类型 | 说明 | 使用场景 |
---|---|---|
前置通知(Before) | 在目标方法被执行之前调用通知 | |
后置通知(After) | 无论如何都会在目标方法执行之后调用通知 | 记录日志(方法已经调用,但不一定成功) |
返回通知(After-returning ) | 在目标方法正常返回后执行通知,如果方法没有正常返返回,例如抛出异常,则返回通知不会执行,可以通过配置得到目标方法的返回值 | 记录日志(方法已经成功调用) |
异常通知(After-throwing) | 在目标方法抛出异常后调用通知 | 异常处理 |
环绕通知(Around) | 通知包裹了目标方法,在目标方法调用之前和调用之后执行自定义的行为 | 事务权限控制 |
Spring Beans
解释Spring支持的几种bean的作用域
当定义一个bean在Spring里,我们还能给这个bean声明一个作用域。它可以通过bean的scope属性来定义。
Spring框架支持以下五种bean的作用域:
作用域 | 描述 |
---|---|
singleton | 单例模式,在spring IoC容器仅存在一个Bean实例,默认值 |
prototype | 原型模式,每次从容器中获取Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅在基于web的Spring ApplicationContext环境下有效 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,该作用域仅在基于web的Spring ApplicationContext环境下有效 |
global-session | 同一个全局的HTTP Session中共享一个Bean,一般用于Portlet应用环境,该作用域仅在基于web的Spring ApplicationContext环境下有效 |
注意: 缺省的Spring bean 的作用域是Singleton。使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。
Spring框架中的单例bean是线程安全的吗?
不是,Spring框架中的单例bean不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
实际上大部分时候 spring bean 是无状态的(比如 dao 类),所以某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
有状态和无状态区别
-
有状态就是有数据存储功能。
-
无状态就是不会保存数据。
Spring如何处理线程并发问题?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中共享变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
解释Spring框架中bean的生命周期
在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例化,然后该bean就可以使用了。一旦该bean不再被使用,则由Java自动进行垃圾回收。相比之下,Spring容器中的bean的生命周期就显得相对复杂多了。正确理解Spring bean的生命周期非常重要,因为你或许要利用Spring提供的扩展点来自定义bean的创建过程。下图展示了bean装载到Spring应用上下文中的一个典型的生命周期过程。
bean在Spring容器中从创建到销毁经历了若干阶段,每一阶段都可以针对Spring如何管理bean进行个性化定制。
正如你所见,在bean准备就绪之前,bean工厂执行了若干启动步骤。
我们对上图进行详细描述:
Spring对bean进行实例化;
Spring将值和bean的引用注入到bean对应的属性中;
如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;
如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似地,如果bean使用initmethod声明了初始化方法,该方法也会被调用;
此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
现在你已经了解了如何创建和加载一个Spring容器。但是一个空的容器并没有太大的价值,在你把东西放进去之前,它里面什么都没有。为了从Spring的DI(依赖注入)中受益,我们必须将应用对象装配进Spring容器中。
Spring注解
使用@Autowired注解自动装配bean的过程是怎样的?
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置<context:annotation-config />
标签,然后在启动spring IoC时,容器就会自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
-
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的属性;
-
如果查询的结果不止一个,会抛出异常,需要配合@Qualifier注解根据名称来查找;
-
如果配合@Qualifier注解根据名称来查找的结果为空,会抛出异常,可以将@Autowire注解的required属性设置为false。
@Autowired和@Resource之间的区别
@Autowired和@Resource都可用于:构造函数、Setter方法、成员变量 ,都可以用来装配bean
@Autowired和@Resource之间的区别
-
@Autowired默认按类型装配(这个注解是属于spring的),@Resource 是JDK1.6支持的注解,默认按照名称进行装配
-
@Autowired默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
@Autowired
@Qualifier("baseDao")
private BaseDao baseDao;
Resource名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="baseDao")
private BaseDao baseDao;
-
其实@Autowired + @Qualifier("BWM") == @Resource(name="BWM"),如果当一个接口只有一个实现类,使用@Autowired和@Resource没有区别,但是最好用@Autowired
@Component, @Controller, @Service, @Repository有何区别?
这四个注解都可以将bean注入到spring容器中,根据不同的使用场景定义了特定功能的注解组件
@Controller用于标注控制层组件
@Service用于标注业务层组件
@Repository用于标注数据访问层组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注
数据访问
Spring支持的事务管理类型, Spring事务实现方式有哪些?你更倾向用哪种事务管理类型?
Spring支持两种类型的事务管理:
编程式事务管理:通过编程的方式管理事务,灵活性好,但是难维护。
声明式事务管理:将业务代码和事务管理分离,只需用注解和XML配置来管理事务。
大多数情况下选择声明式事务管理,虽然比编程式事务管理少了一点灵活性,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别,但是声明式事务管理对应用代码的影响最小,更符合一个无侵入的轻量级容器的思想,具有更好的可维护性。
Spring事务的实现方式和实现原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过bin log或者redo log实现的。
说一下Spring的事务传播行为
spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
说一下 spring 的事务隔离级别?
spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:
-
ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
-
ISOLATION_READ_UNCOMMITTED:读未提交,最低的隔离级别,一个事务可以读取另一个事务更新但未提交的数据。(会出现脏读、不可重复读、幻读);
-
ISOLATION_READ_COMMITTED:读已提交,一个事务提交后才能被其他事务读取到(会出现不可重复读、幻读),Oracle、SQL server 的默认级别;
-
ISOLATION_REPEATABLE_READ:可重复读,对同一字段的多次读取结果都是一致的,除非数据被本身事务所修改(会出现幻读),MySQL 的默认级别;
-
ISOLATION_SERIALIZABLE:可串行化,最高的隔离级别,可以防止脏读、不可重复读、幻读。
Spring框架的事务管理有哪些优点?
-
为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式。
-
为编程式事务管理提供了一套简单的API而不是一些复杂的事务API
-
支持声明式事务管理。
-
和Spring各种数据访问抽象层很好得集成。