Spring事务传播机制
spring的事务传播机制

spring的事务传播机制
多个事务⽅法相互调⽤时,事务如何在这些⽅法之间进⾏传播,spring中提供了7中不同的传播特性,来保证事务的正常执⾏:REQUIRED:默认的传播特性,如果当前没有事务,则新建⼀个事务,如果当前存在事务,则加⼊这个事务
SUPPORTS:当前存在事务,则加⼊当前事务,如果当前没有事务,则以⾮事务的⽅式执⾏
MANDATORY:当前存在事务,则加⼊当前事务,如果当前事务不存在,则抛出异常
REQUIRED_NEW:创建⼀个新事务,如果存在当前事务,则挂起改事务
NOT_SUPPORTED:以⾮事务⽅式执⾏,如果存在当前事务,则挂起当前事务
NEVER:不使⽤事务,如果当前事务存在,则抛出异常
NESTED:如果当前事务存在,则在嵌套事务中执⾏,否则REQUIRED的操作⼀样
NESTED和REQUIRED_NEW的区别:
REQUIRED NEW是新建⼀个事务并且新开始的这个事务与原有事务⽆关,⽽NESTED则是当前存在事务时会开启⼀个嵌套事务,在NESTED情况下,⽗事务回滚时,⼦事务也会回滚,⽽REQUIRED NEW情况下,原有事务回滚,不会影响新开启的事务
NESTED和REQUIRED的区别:
REQUIRED情况下,调⽤⽅存在事务时,则被调⽤⽅和调⽤⽅使⽤同⼀个事务,那么被调⽤⽅出现异常时,由于共⽤⼀个事务,所以⽆论是否catch异常,事务都会回滚,⽽在NESTED情况下,被调⽤⽅发⽣异常时,调⽤⽅可以catch其异常,这样只有⼦事务回滚,⽗事务不会回滚。
这一次搞懂Spring事务是如何传播的

这⼀次搞懂Spring事务是如何传播的前⾔上⼀篇分析了,本质上是将事务封装为切⾯加⼊到AOP的执⾏链中,因此会调⽤到MethodInceptor的实现类的invoke⽅法,⽽事务切⾯的Interceptor就是TransactionInterceptor,所以本篇直接从该类开始。
正⽂事务切⾯的调⽤过程public Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}这个⽅法本⾝没做什么事,主要是调⽤了⽗类的invokeWithinTransaction⽅法,注意最后⼀个参数,传⼊的是⼀个lambda表达式,⽽这个表达式中的调⽤的⽅法应该不陌⽣,在分析AOP调⽤链时,就是通过这个⽅法传递到下⼀个切⾯或是调⽤被代理实例的⽅法,忘记了的可以回去看看。
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.//获取事务属性类 AnnotationTransactionAttributeSourceTransactionAttributeSource tas = getTransactionAttributeSource();//获取⽅法上⾯有@Transactional注解的属性final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);//获取事务管理器final PlatformTransactionManager tm = determineTransactionManager(txAttr);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal = null;try {// 调⽤proceed⽅法retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception//事务回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}//事务提交commitTransactionAfterReturning(txInfo);return retVal;}// 省略了else}这个⽅法逻辑很清晰,⼀⽬了然,if⾥⾯就是对声明式事务的处理,先调⽤createTransactionIfNecessary⽅法开启事务,然后通过invocation.proceedWithInvocation调⽤下⼀个切⾯,如果没有其它切⾯了,就是调⽤被代理类的⽅法,出现异常就回滚,否则提交事务,这就是Spring事务切⾯的执⾏过程。
Spring事务隔离级别和传播机制

Spring事务隔离级别和传播机制引⾔什么是事务?在理解事务之前,我们要先了解事务的基本作⽤⽐如在⽣活中有这样⼀个场景————取钱,每个⼈应该都⼲过的事在ATM机上取钱,1.输⼊密码————2.输⼊⾦额————3.银⾏扣钱————4.ATM出钱以上⼏个步骤中,3和4就是必须是⼀个事务,因为它们之间,要么都完成,要么都不完成事务其实就是⽤来解决这种类似的问题想象⼀理,如果第3步成功了,第4步失败(报错)了,这将会导致⾮常严重的后果,对于普通⼈⽽⾔,钱被扣了,但ATM机没出钱,肯定会发飙的吧。
哈哈所以第3步和第4步,必须要全部被执⾏完成,这样才能保证最后数据的⼀致性。
对应到业务开发过程中,第3步和第4步,我们把它认为是⼀个执⾏单元,但在代码⾥⾯它是⼀条条的代码,所以必须要有⼀种机制能够保证它们要么全部执⾏成功,要么全部执⾏失败。
在企业级应⽤程序开发中,事务管理是必不可少的技术,⽤来确保数据的完整性和⼀致性。
Spring事务是建⽴在持久层的基础之上的,要理解Spring事务,就必须要先了解事务的相关特性事务特性1. 原⼦性(Atomicity)事务是⼀个原⼦操作,由⼀系列动作组成。
事务的原⼦性确保动作要么全部完成,要么完全不起作⽤。
2. ⼀致性(Consistency)⼀旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于⼀致的状态,⽽不会是部分完成部分失败。
在现实中的数据不应该被破坏。
3. 隔离性(Isolation)可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防⽌数据损坏。
4. 持久性(Durability)⼀旦事务完成,⽆论发⽣什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。
通常情况下,事务的结果被写到持久化存储器中。
Mysql事务实现1.获取连接2.关闭⾃动提交功能(SET AUTOCOMMIT = FALSE)3.开启事务4.业务SQL语句5.提交事务6.打开⾃动提交功能(SET AUTOCOMMIT = TRUE)7.关闭连接Mysql(InnoDB)实现源码Spring事务实现原理Spring⽀持编程式事务管理以及声明式事务管理两种⽅式。
Spring的事务传播特性

Spring的事务传播特性
在spring中可通过使⽤注解@Transcation( propagation = "传播机制")实现事务的传播,Spring中有7种传播机制
1.默认传播:PROPAGATION_REQUIRED
⽀持当前的事务,如果当前没有事务,就新建事务;
如果当前已有事务,则合并为⼀个事务。
解释:如果有个⽗⽅法A和⼦⽅法B,只要有⼀个带有事务,那么A和B都将拥有事务。
2.独⽴事务:REQUIRES_NEW
如果当前已拥有事务,则把当前事务挂起,新建事务
该机制下的事务不受其它调⽤者事务的影响
解释:如果有个⽗⽅法A(有事务)和⼦⽅法B(有事务),如果A抛出异常,⽽B使⽤了这个声明事务,那么B仍会继续提交(不受A事务影响)
3.NESTED
如果当前存在事务,它将会成为⽗级的⼀个⼦事务,⽅法结束后并没有提交,只是等待⽗事务结束才提交。
如果当前没有事务,则新建事务。
如果它本⾝异常,⽗级可以捕获到它的异常,⽽不进⾏回滚。
正常提交。
但是如果⽗级异常,它必然回滚。
解释:⼀切以⽗级事务为主
4.SUPPORTS
若当前已有事务,则加⼊事务;
若当前没有事务,则以⽆事务进⾏;
解释:佛系事务,有就⽤,没有就不⽤了
5.NOT_SUPPORTS
不⽀持事务,如果当前有事务,则把该事物挂起
6.MAMDATORY
若当前有事务,则运⾏当前事务;
若当前没有实物,则抛异常;
解释:⽗级若没有事务,就不⼲了
7.NEVER
有事务就抛异常。
transactiontemplate 事务传播机制

transactiontemplate 事务传播机制事务传播机制是指在一个事务中,如果存在多个事务操作,各个事务之间是如何进行协调和传播的。
在Spring框架中,可以使用TransactionTemplate来管理事务的传播行为。
TransactionTemplate是Spring提供的一个用于编程式事务管理的工具类。
它封装了事务的创建、提交、回滚等操作,提供了一种简单而灵活的方式来管理事务。
在TransactionTemplate中,可以通过设置事务传播行为来控制事务的传播机制。
事务传播行为有以下几种:1. PROPAGATION_REQUIRED(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
这是最常用的传播行为,它保证了一组操作要么都成功,要么都失败。
2. PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。
这种传播行为适用于不需要事务支持的操作。
3. PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
这种传播行为适用于必须在事务中执行的操作,如果没有事务则会抛出异常。
4. PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则将当前事务挂起。
这种传播行为适用于需要独立的事务执行的操作,它会暂停当前的事务,创建一个新的事务来执行操作。
5. PROPAGATION_NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,则将当前事务挂起。
这种传播行为适用于不需要事务支持的操作,它会暂停当前的事务,以非事务的方式执行操作。
6. PROPAGATION_NEVER:以非事务的方式执行操作,如果当前存在事务,则抛出异常。
这种传播行为适用于不允许在事务中执行的操作,如果存在事务则会抛出异常。
7. PROPAGATION_NESTED:如果当前存在事务,则创建一个嵌套事务来执行操作;如果当前没有事务,则创建一个新的事务。
Spring事务传播机制

Spring事务传播机制Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,并且实现者需要支持保存点事务机制。
几种容易引起误解的组合事务传播行为当服务接口方法分别使用表1中不同的事务传播行为,且这些接口方法又发生相互调用的情况下,大部分组合都是一目了然,容易理解的。
但是,也存在一些容易引起误解的组合事务传播方式。
下面的例子中有两个service:UserService和ForumService, UserSerice有一个addCredits()方法,ForumSerivce#addTopic()方法调用了 UserSerice#addCredits()方法,发生关联性服务方法的调用:public class ForumService {private UserService userService;public void addTopic(){ //①调用其它服务接口的方法userService.addCredits();//②被关联调用的业务方法}}开发者认为:应尽量不让Service类的业务方法发生相互的调用,Service类只能调用DAO层的DAO类,以避免产生嵌套事务。
其实,这种顾虑是完全没有必要的,PROPAGATION_REQUIRED已经清楚地告诉我们:事务的方法会足够“聪明”地判断上下文是否已经存在一个事务中,如果已经存在,就加入到这个事务中,否则创建一个新的事务。
依照上面的例子,假设我们将ForumService#addTopic()设置为PROPAGATION_REQUIRED 时, UserSerice#addCredits()设置为PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY时,都是在同一事务中。
Spring事务的隔离级别和传播机制

Spring事务的隔离级别和传播机制七个传播机制:(红⾊字体的代表如果不设置传播机制时候默认的)
PROPAGATION_REQUIRED-⽀持当前事务;如果不存在,创建⼀个新的。
PROPAGATION_SUPPORTS-⽀持当前事务;如果当前事务不存在,按⾮事务执⾏。
PROPAGATION_MANDATORY-⽀持当前事务;如果没有当前事务,则抛出异常的存在。
PROPAGATION_REQUIRES_NEW-创建⼀个新事务,如果当前事务存在,则挂起当前事务。
PROPAGATION_NOT_SUPPORTED-不⽀持当前事务;⽽是始终以⾮事务⽅式执⾏。
PROPAGATION_NEVER-不⽀持当前事务;如果当前事务引发异常的存在。
PROPAGATION_NESTED-如果当前事务存在,则在嵌套事务中执⾏。
五个隔离级别:(红⾊字体的代表如果不设置传播机制时候默认的)
ISOLATION_DEFAULT-使⽤底层数据存储的默认隔离级别。
所有其他级别都对应JDBC隔离级别。
ISOLATION_READ_UNCOMMITTED-读未提交(表⽰脏读、不可重复读和幻读可能发⽣)
ISOLATION_READ_COMMITTED-读已提交(表⽰禁⽌脏读;不可重复读和可能发⽣幻读。
)
ISOLATION_REPEATABLE_READ-不可重复读(表⽰防⽌脏读和不可重复读;可能发⽣幻读。
)
ISOLATION_SERIALIZABLE-序列化(表⽰脏读、不可重复读和幻读不会发⽣。
)。
Spring事务管理中的七种传播机制及示例讲解

Spring事务管理中的七种传播机制及⽰例讲解课程分组的时候分到了Spring传播机制的内容,研究整理了⼀下。
⼀、事务传播⾏为和事务传播机制事务传播⾏为:⼀般发⽣在事务嵌套的场景中,⽐如⼀个有事务的⽅法⾥⾯调⽤了另外⼀个有事务的⽅法这个时候就会产⽣事务边界控制的问题,即两个⽅法是各⾃作为独⽴的事务提交还是内层的事务合并到外层的事务⼀起提交Spring规定了七⼤传播机制来解决边界控制的问题。
⼆、七⼤传播机制传播机制说明PROPAGATION_REQUIRED如果当前没有事务,就新建⼀个事务,如果已经存在⼀个事务中,加⼊到这个事务中。
这是最常见的选择。
PROPAGATION_SUPPORTS⽀持当前事务,如果当前没有事务,就以⾮事务⽅式执⾏。
PROPAGATION_MANDATORY使⽤当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER以⾮事务⽅式执⾏,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执⾏。
如果当前没有事务,则执⾏与PROPAGATION_REQUIRED类似的操作。
三、对⽐理解及举例第⼀组传播机制通俗解释PROPAGATION_NEVER强制以⾮事务的⽅式运⾏,外层有事务,将会产⽣异常PROPAGATION_MANDATORY强制加⼊外层事务,外层没有事务,则会产⽣异常举例:在充值处理这个业务中,调⽤了扣款和订单⽣成两个⽅法,充值处理业务需要扣款操作和订单⽣成操作同成功或者失败,所以需要把这两个⽅法放到同⼀个事务中运⾏;所以可以指定这两个⽅法的传播机制为MANDATORY,这样它们就会都加⼊到外层事务,处于⼀个事务中,可以保证同成功或失败。
「聊一聊Spring」Spring的事务传播行为

「聊⼀聊Spring 」Spring 的事务传播⾏为Spring中的事务传播⾏为事务管理并⾮ Spring ⾸创,Spring 也借鉴了很多其他的框架,然后加以统⼀。
在 Spring 中,我们经常使⽤声明式事务,在⽅法或类上添加 Spring 的 @Transtional 注解,在这个注解中我们可以指定事务传播⾏为,这个注解也参考了 EJB 的javax.ejb.TransactionAttribute 以及 JTA 的 javax.transaction.Transactional,这⾥先通过对⽐认识⼀下这三者的异同。
从上⾯的表格中可以看到,在 Spring 的 @Transactional 中都可以找到 EJB、JTA 注解中相应的参数。
事实上,Spring 也对 EJB 的 @TransactionAttribute 注解及 JTA 的@Transactional 加以了⽀持,在 Spring 中这三个注解都可以使⽤。
现在将重点转向事务传播⾏为,上⾯的三个注解都有事务传播⾏为,那么这三者的事务传播⾏为⼜有何异同呢?有没有发现⼀些问题?Spring 中的事务定义与 EJB、JTA 基本⼀致,它们名称不仅相同,事实上语义和实现也相似,⽽且 Spring 还增加了⼀个 NESTED 类型的事务传播⾏为。
事务传播⾏为主要是控制新⽅法执⾏时是否使⽤事务,如何处理线程中以存在的事务。
下⾯是对 Spring 中的这7中事务传播⾏为的描述:REQUIRED :默认的事务传播⾏为;需要事务:存在事务则使⽤已存在事务,否则创建新的事务;SUPPORTS :⽀持已存在事务:存在事务则使⽤已存在事务,否则以⾮事务⽅式运⾏;MANDATORY :强制使⽤事务:存在事务则使⽤已存在事务,否则抛出异常;REQUIRES_NEW :需要新事务:存在事务则挂起已存在事务,否则创建新事务;NOT_SUPPORTED :不⽀持事务:存在事务则挂起已存在事务,否则以⾮事务⽅式运⾏;NEVER :从不使⽤事务:存在事务则抛出异常,否则以⾮事务⽅式运⾏;NESTED :嵌套事务:存在事务则使创建保存点使⽤嵌套的事务,否则创建新的事务。
Spring事务的传播机制

Spring事务的传播机制Spring事务的传播机制是指在多个事务方法相互调用的情况下,事务的传播规则和行为。
Spring框架提供了七种事务传播行为,分别为REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。
1.REQUIRED(默认):如果当前存在事务,则加入该事务,如果不存在事务,则创建一个新事务。
该传播行为是最常用的一种,适用于大多数业务场景。
例如,A方法调用B方法,B方法中使用REQUIRED传播行为,则B方法会加入A方法的事务中。
2.SUPPORTS:如果当前存在事务,则加入该事务,如果不存在事务,则以非事务的方式执行。
该传播行为适用于不需要强制事务的情况。
例如,A方法调用B方法,B方法中使用SUPPORTS传播行为,则B方法会根据当前是否存在事务来决定是否加入。
3.MANDATORY:如果当前存在事务,则加入该事务,如果不存在事务,则抛出异常。
该传播行为适用于必须在事务中执行的情况。
例如,A方法调用B方法,B方法中使用MANDATORY传播行为,则B方法会检查当前是否存在事务,如果不存在则抛出异常。
4.REQUIRES_NEW:无论当前是否存在事务,都创建一个新事务,并在新事务中执行。
该传播行为适用于需要独立事务执行的情况。
例如,A方法调用B方法,B方法中使用REQUIRES_NEW传播行为,则B方法会创建一个新事务并在其中执行。
5.NOT_SUPPORTED:以非事务的方式执行方法,如果当前存在事务,则将事务挂起。
该传播行为适用于不需要事务的情况。
例如,A方法调用B方法,B方法中使用NOT_SUPPORTED传播行为,则B方法会以非事务的方式执行。
6.NEVER:以非事务的方式执行方法,如果当前存在事务,则抛出异常。
该传播行为适用于必须在非事务中执行的情况。
例如,A方法调用B方法,B方法中使用NEVER传播行为,则B方法会检查当前是否存在事务,如果存在则抛出异常。
Spring事务传播机制

Spring事务传播机制 spring的管理的事务可以分为如下2类:逻辑事务:在spring中定义的事务通常指逻辑事务,提供⽐物理事务更抽象,⽅便的事务配置管理,但也基于物理事务物理事务:特定于数据库的事务 spring中⽀持⼀下2中事务声明⽅式编程式事务:当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务声明式事务:当系统对于事务的控制粒度较粗时,应该选择申明式事 ⽆论你选择上述何种事务⽅式去实现事务控制,spring都提供基于门⾯设计模式的事务管理器供选择,如下是spring事务中⽀持的事务管理器UML结构图如下1.各种事务管理器的定义如下JdbcTransactionManager定义如下<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource"ref="dataSource"/></bean>View Codehibernate事务管理器配置如下<bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"/></bean>View Code hibernate的事务管理器会注⼊session会话⼯⼚,然后将事务处理委托给当前的transaction对象,事务提交时,调⽤commit()⽅法,回滚时调⽤rollback()⽅法.其余事务管理器可参见spring in action中说明。
Spring事务的传播机制

Spring事务的传播机制Spring提供了事务的注解属性propagation [ˌprɒpə'ɡeɪʃ(ə)n] 传播⼀共有7种事务传播机制下⾯通过a.save()调⽤b.save()解释事务的传播机制REQUIRED:(必须的)Spring的默认传播级别,如果上下⽂中存在事务则加⼊当前事务,如果不存在事务则新建事务执⾏。
PS:a.save和b.save的事务传播机制都是REQUIRED,b.save的事务是跟着a.save的;若a.save没有事务,b.save的传播机制为REQUIRED,则b.save出现异常会回滚SUPPORTS:(⽀持)如果上下⽂中存在事务则加⼊当前事务,如果没有事务则以⾮事务⽅式执⾏。
PS:若a.save开启了事务则b.save就有事务,若a.save没有事务,b.save的事务传播机制为SUPPORTS,那么b.save也没有事务-出现异常不会回滚。
MANDATORY:([ˈmændətəri] 强制的)该传播级别要求上下⽂中必须存在事务,否则抛出异常。
PS:当b.save的事务传播机制为MANDATORY时,如果a.save不开启事务,则会抛出下⾯的异常REQUIRES_NEW:(开启新的事务)该传播级别每次执⾏都会创建新事务,并同时将上下⽂中的事务挂起,执⾏完当前线程后再恢复上下⽂中事务。
(⼦事务的执⾏结果不影响⽗事务的执⾏和回滚)PS:当b.save的事务传播机制为REQUIRES_NEW时,a.save发⽣异常(a.save会回滚),但是不会影响b.save的事务提交,也就是b.save正常执⾏;b.save发⽣了异常,b的事务会回滚,但不会影响a.save的事务NOT_SUPPORTED:(不⽀持事务)当上下⽂中有事务则挂起当前事务,执⾏完当前逻辑后再恢复上下⽂事务。
(降低事务⼤⼩,将⾮核⼼的执⾏逻辑包裹执⾏。
)PS:当a.save开启事务,b.save的事务传播机制为NOT_SUPPORTED时,b.save是不⽀持事务的,b.save发⽣异常不会回滚,但是不会影响a.save的事务,所以a.save会回滚NEVER:(绝不要事务)该传播级别要求上下⽂中不能存在事务,否则抛出异常。
事务传播机制

事务传播机制Spring 事务——事务的传播机制⼀、什么是事务的传播?简单的理解就是多个事务⽅法相互调⽤时,事务如何在这些⽅法间传播。
举个栗⼦,⽅法A是⼀个事务的⽅法,⽅法A执⾏过程中调⽤了⽅法B,那么⽅法B有⽆事务以及⽅法B对事务的要求不同都会对⽅法A的事务具体执⾏造成影响,同时⽅法A的事务对⽅法B的事务执⾏也有影响,这种影响具体是什么就由两个⽅法所定义的事务传播类型所决定。
⼆、Spring事务传播类型枚举Propagation介绍spring在TransactionDefinition接⼝中定义了七个事务传播⾏为:propagation_requierd:如果当前没有事务,就新建⼀个事务,如果已存在⼀个事务中,加⼊到这个事务中,这是最常见的选择。
propagation_supports:⽀持当前事务,如果没有当前事务,就以⾮事务⽅法执⾏。
propagation_mandatory:使⽤当前事务,如果没有当前事务,就抛出异常。
propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
propagation_not_supported:以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。
propagation_never:以⾮事务⽅式执⾏操作,如果当前事务存在则抛出异常。
propagation_nested:如果当前存在事务,则在嵌套事务内执⾏。
如果当前没有事务,则执⾏与propagation_required类似的操作REQUIRED(Spring默认的事务传播类型)如果当前没有事务,则⾃⼰新建⼀个事务,如果当前存在事务,则加⼊这个事务源码说明如下:/*** Support a current transaction, create a new one if none exists.* Analogous to EJB transaction attribute of the same name.* <p>This is the default setting of a transaction annotation.*/REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),(⽰例1)根据场景举栗⼦,我们在testMain和testB上声明事务,设置传播⾏为REQUIRED,伪代码如下:@Transactional(propagation = Propagation.REQUIRED)public void testMain(){A(a1); //调⽤A⼊参a1testB(); //调⽤testB}@Transactional(propagation = Propagation.REQUIRED)public void testB(){B(b1); //调⽤B⼊参b1throw Exception; //发⽣异常抛出B(b2); //调⽤B⼊参b2}该场景下执⾏testMain⽅法结果如何呢?数据库没有插⼊新的数据,数据库还是保持着执⾏testMain⽅法之前的状态,没有发⽣改变。
Spring事务传播机制

Spring事务传播机制概述当我们调用一个基于Spring的Service接口办法(如UserServiceaUser())时,它将运行于Spring管理的事务环境中,Service接口办法可能会在内部调用其它的Service接口办法以共同完成一个完整的业务操作,因此就会产生服务接口办法嵌套调用的状况,Spring通过事务传扬行为控制当前的事务如何传扬到被嵌套调用的目标服务接口办法中。
事务传扬是Spring举行事务管理的重要概念,其重要性怎么强调都不为过。
但是事务传扬行为也是被误会最多的地方,在本文里,我们将具体分析不同事务传扬行为的表现形式,把握它们之间的区分。
事务传扬行为种类 Spring在TransactionDefinition接口中规定了7种类型的事务传扬行为,它们规定了事务办法和事务办法发生嵌套调用时事务如何举行传扬:表1事务传扬行为类型事务传扬行为类型解释 PROPAGATION_REQUIRED 假如当前没有事务,就新建一个事务,假如已经存在一个事务中,加入到这个事务中。
这是最频繁的挑选。
PROPAGATION_SUPPORTS 支持当前事务,假如当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 用法当前的事务,假如当前没有事务,就抛出异样。
PROPAGATION_REQUIRES_NEW 新建事务,假如当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,假如当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,假如当前存在事务,则抛出异样。
PROPAGATION_NESTED 假如当前存在事务,则在嵌套事务内执行。
假如当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
当用法PROPAGATION_NESTED时,底层的数据源必需基于JDBC 3.0,并且实现者需要支持保存点事务机制。
spring的传播机制

spring的传播机制前⾔:Spring的事务,也就是数据库的事务操作,符合ACID标准,也具有标准的事务隔离级别。
但是Spring事务有⾃⼰的特点,也就是事务传播机制。
所谓事务传播机制,也就是在事务在多个⽅法的调⽤中是如何传递的,是重新创建事务还是使⽤⽗⽅法的事务?⽗⽅法的回滚对⼦⽅法的事务是否有影响?这些都是可以通过事务传播机制来决定的。
本⽂就测试⼀下这些事务传播机制的使⽤及异同1.准备测试⽅法主要是创建两个service接⼝(接⼝主要是对数据库表的操作),并创建其实现类1)创建beans.xml,开启事务<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/tx/schema/tx/spring-tx.xsd/schema/aop/schema/aop/spring-aop.xsd"><tx:annotation-driven transaction-manager="transactionManager"/></beans>2)创建实体类和表(表创建读者可⾃定义创建)@Data@AllArgsConstructor@NoArgsConstructorpublic class Blog {private int id;private String name;private String ur;}3)创建service接⼝(BlogService和BlogService2,主要是对Blog的不同操作)// BlogServicepackage jdbc;// 主要负责Blog的添加和修改public interface BlogService {void save(Blog blog);void update(Blog blog);}// BlogService2package jdbc;// 主要负责Blog的删除public interface BlogService2 {void delete(int id);}4)创建其实现类(BlogServiceImpl,BlogService2)BlogServiceImpl.java@Transactional(propagation=Propagation.REQUIRED)@Componentpublic class BlogServiceImpl implements BlogService {@Autowiredprivate JdbcTemplate jdbcTemplate;@Autowiredprivate BlogService2 blogService2;@Overridepublic void save(Blog blog) {String sql = "insert into blog values(?,?,?)";jdbcTemplate.update(sql,new Object[]{blog.getId(),blog.getName(),blog.getUr()},new int[]{java.sql.Types.INTEGER,java.sql.Types.VARCHAR,java.sql.Types.VARCHAR});blogService2.delete(16);// update(blog);// throw new RuntimeException("error");}@Overridepublic void update(Blog blog){String sql = "update blog set name = ? where id=?";jdbcTemplate.update(sql, new Object[]{blog.getName(),blog.getId()},new int[]{java.sql.Types.VARCHAR,java.sql.Types.INTEGER});}}BlogService2.java@Transactional(propagation=Propagation.REQUIRED)@Componentpublic class BlogServiceImpl2 implements BlogService2 {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void delete(int id){String sql = "delete from blog where id=?";jdbcTemplate.update(sql, id);}}注意:既然要实现多事务的传播,就需要在⼀个⽅法⾥调⽤另⼀个类的⽅法,下⾯的测试就是基于这种⽅法,在BlogService的save()⽅法中调⽤BlogService2的delete()⽅法5)创建Configuration类,⽤于创建DataSource实现@Configuration@ComponentScan(basePackages={"jdbc"})// 扫描BlogService实现类所在的包路径@ImportResource(locations={"classpath:beans.xml"})// 添加事务管理public class JdbcConfig {@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){return new JdbcTemplate(dataSource);}@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);}@Beanpublic DataSource dataSource(){try {return new SimpleDriverDataSource(new com.mysql.jdbc.Driver(), "jdbc:mysql://localhost:3306/test", "root", "root");} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}}6)测试public class Test {public static void main(String[] args) {AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(JdbcConfig.class);BlogService service = ac.getBean(BlogService.class);Blog b = new Blog(18,"lili","url");service.save(b);}}总结:⼤体的测试框架就如上所⽰,下⾯的测试修改主要是修改BlogServiceImpl和BlogServiceImpl2的事务传播机制@Transactional(propagation=Propagation.REQUIRED)3.事务传播机制的测试1)REQUIRED定义:如果有事务则加⼊事务,如果没有事务,则创建⼀个新的(默认值)操作1:将BlogServiceImpl和BlogServiceImpl2的事务传播机制都修改为@Transactional(propagation=Propagation.REQUIRED)结果1:操作2:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.REQUIRED)结果2:总结:当BlogServiceImpl提供事务的时候,BlogServiceImpl2的⽅法执⾏使⽤当前已有事务,不再新建事务;当BlogServiceImpl不创建事务的时候,BlogServiceImpl2的⽅法执⾏发现没有事务可⽤,⾃⼰新建事务;2)NOT_SUPPORTED定义:Spring不为当前⽅法开启事务,相当于没有事务操作:将BlogServiceImpl和BlogServiceImpl2的事务传播机制都修改为@Transactional(propagation=Propagation.NOT_SUPPORTED)结果:总结:NOT_SUPPORTED相当于没有Spring事务,每条执⾏语句单独执⾏,单独提交3)REQUIRES_NEW定义:不管是否存在事务,都创建⼀个新的事务,原来的⽅法挂起,新的⽅法执⾏完毕后,继续执⾏⽼的事务操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.REQUIRES_NEW)结果:总结:REQUIRES_NEW为当前⽅法创建⼀个新的事务,并且当前事务先提交,然后再提交⽼的事务4)MANDATORY定义:必须在⼀个已有的事务中执⾏,否则报错操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.MANDATORY),查看是否报错结果:总结:MANDATORY必须在已有事务下被调⽤,否则报错NOT_SUPPORTED执⾏数据库层⾯的事务操作,故当前测试中,insert⽅法成功执⾏,delete⽅法的抛错并不影响insert⽅法的执⾏5)NEVER定义:必须在⼀个没有的事务中执⾏,否则报错操作:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.MANDATORY),查看是否报错结果:总结:NEVER必须在没有事务的⽅法中执⾏,否则报错;save⽅法开启⼀个事务,还没来及提交发现delete⽅法报错,只能回滚事务6)SUPPORTS定义:如果其他bean调⽤这个⽅法时,其他bean声明了事务,则就⽤这个事务,如果没有声明事务,那就不⽤事务操作1:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.SUPPORTS)结果1:操作1:将BlogServiceImpl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),BlogServiceImpl2的仍为@Transactional(propagation=Propagation.SUPPORTS)结果1:总结:SUPPORTS类型的事务传播机制,是否使⽤事务取决于调⽤⽅法是否有事务,如果有则直接⽤,如果没有则不使⽤事务7)NESTED定义:如果当前存在事务,则在嵌套事务内执⾏。
Spring事务传播机制

Spring事务传播机制⼀、什么是事务传播机制事务传播机制是当⼀个事务⽅法被另⼀个事务⽅法调⽤时,这个事务⽅法应该如何去执⾏,例如method1⽅法添加了事务,去调⽤了method2事务⽅法,那么method2是继续在method1的事务中执⾏,还是新开⼀个事务时执⾏,这就需要method2的事务传播机制来决定。
在Spring中。
事务控制是基于AOP实现的,它给我们提供了⼀个注解@Transactional,所以在实际中我们只需要使⽤这个注解就⾏了。
⼆、为什么需要⼀个事务传播机制在Spring中。
我们不⽤去关⼼事务是什么时候开始、提交或者回滚的。
但是在这其中会出现⼀些问题,⽐如在两个service中:① service1的⽅法调⽤了service2的⽅法,这两个⽅法都有事务,这时如果service2的⽅法发⽣异常,是让service2提交还是两个⽅法⼀起回滚;② service1的⽅法调⽤了service2的⽅法,但是只有service1的⽅法加了事务,这时是否将service2也加⼊到service1的事务中去,如果service2的⽅法发⽣异常,是否需要回滚service1;③ service1的⽅法调⽤了service2的⽅法,这两个⽅法都有事务,service2的⽅法已经执⾏完毕,紧接着继续执⾏service1的后续代码,这时发⽣异常,是否需要回滚service2⽅法。
三、7种事务传播⾏为在开始介绍之前,我们⾸先要明确⼀点,Spring是使⽤的AOP代理的事务控制,它是针对于接⼝和类的,如果在同⼀个service类中的两个⽅法相互调⽤,传播机制并不会⽣效。
传播⾏为含义PROPAGATION_REQUIRED 这是默认的传播⾏为。
表⽰当前⽅法必须运⾏在事务中,如果当前事务存在,就直接使⽤这个事务,否则,开启⼀个新的事务。
简单地说就是,如果存在事务,就⽤该事务,否则就创建⼀个事务拿来⽤。
PROPAGATION_REQUIRED_NEW 表⽰当前⽅法必须运⾏在⾃⼰的事务中,会启动⼀个新的事务,如果存在当前事务,在执⾏期间就会挂起当前事务。
Spring事务配置的五种方式和spring里面事务的传播属性和事务隔离级别

Spring事务配置的五种⽅式和spring⾥⾯事务的传播属性和事务隔离级别前段时间对Spring的事务配置做了⽐较深⼊的研究,在此之间对Spring的事务配置虽说也配置过,但是⼀直没有⼀个清楚的认识。
通过这次的学习发觉Spring的事务配置只要把思路理清,还是⽐较好掌握的。
总结如下:Spring配置⽂件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,⽆论哪种配置⽅式,⼀般变化的只是代理机制这部分。
DataSource、TransactionManager这两部分只是会根据数据访问⽅式有所变化,⽐如使⽤Hibernate进⾏数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。
具体如下图:根据代理机制的不同,总结了五种Spring事务的配置⽅式,配置⽂件如下:第⼀种⽅式:每个Bean都有⼀个代理<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans-2.5.xsd/schema/context /schema/context/spring-context-2.5.xsd /schema/aop/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"><property name="configLocation" value="classpath:hibernate.cfg.xml" /><property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /></bean><!-- 定义事务管理器(声明式的事务) --><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean><!-- 配置DAO --><bean id="userDaoTarget" class="erDaoImpl"><property name="sessionFactory" ref="sessionFactory" /></bean><bean id="userDao"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"><!-- 配置事务管理器 --><property name="transactionManager" ref="transactionManager" /><property name="target" ref="userDaoTarget" /><property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" /><!-- 配置事务属性 --><property name="transactionAttributes"><props><prop key="*">PROPAGATION_REQUIRED</prop></props></property></bean></beans>第⼆种⽅式:所有Bean共享⼀个代理基类<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans-2.5.xsd/schema/context /schema/context/spring-context-2.5.xsd /schema/aop/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /><property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /></bean><!-- 定义事务管理器(声明式的事务) --><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean><bean id="transactionBase"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true" abstract="true"><!-- 配置事务管理器 --><property name="transactionManager" ref="transactionManager" /><!-- 配置事务属性 --><property name="transactionAttributes"><props><prop key="*">PROPAGATION_REQUIRED</prop></props></property></bean><!-- 配置DAO --><bean id="userDaoTarget" class="erDaoImpl"><property name="sessionFactory" ref="sessionFactory" /></bean><bean id="userDao" parent="transactionBase" ><property name="target" ref="userDaoTarget" /></bean></beans>第三种⽅式:使⽤拦截器<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans-2.5.xsd/schema/context /schema/context/spring-context-2.5.xsd /schema/aop/schema/aop/spring-aop-2.5.xsd"><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /><property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /></bean><!-- 定义事务管理器(声明式的事务) --><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean><bean id="transactionInterceptor"class="org.springframework.transaction.interceptor.TransactionInterceptor"><property name="transactionManager" ref="transactionManager" /><!-- 配置事务属性 --><property name="transactionAttributes"><props><prop key="*">PROPAGATION_REQUIRED</prop></props></property></bean><bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="beanNames"><list><value>*Dao</value></list></property><property name="interceptorNames"><list><value>transactionInterceptor</value></list></property></bean><!-- 配置DAO --><bean id="userDao" class="erDaoImpl"><property name="sessionFactory" ref="sessionFactory" /></bean></beans>第四种⽅式:使⽤tx标签配置的拦截器<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans-2.5.xsd/schema/context /schema/context/spring-context-2.5.xsd /schema/aop/schema/aop/spring-aop-2.5.xsd/schema/tx /schema/tx/spring-tx-2.5.xsd"><context:annotation-config /><context:component-scan base-package="com.bluesky" /><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /><property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /></bean><!-- 定义事务管理器(声明式的事务) --><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="*" propagation="REQUIRED" /></tx:attributes></tx:advice><aop:config><aop:pointcut id="interceptorPointCuts" expression="execution(* com.bluesky.spring.dao.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" /></aop:config></beans>第五种⽅式:全注解<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:aop="/schema/aop"xmlns:tx="/schema/tx"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans-2.5.xsd/schema/context /schema/context/spring-context-2.5.xsd /schema/aop/schema/aop/spring-aop-2.5.xsd/schema/tx /schema/tx/spring-tx-2.5.xsd"><context:annotation-config /><context:component-scan base-package="com.bluesky" /><tx:annotation-driven transaction-manager="transactionManager"/><bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml" /><property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" /></bean><!-- 定义事务管理器(声明式的事务) --><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean></beans>此时在DAO上需加上@Transactional注解,如下:package com.bluesky.spring.dao;import java.util.List;import org.hibernate.SessionFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.orm.hibernate3.support.HibernateDaoSupport;import ponent;import er;@Transactional@Component("userDao")public class UserDaoImpl extends HibernateDaoSupport implements UserDao {public List<User> listUsers() {return this.getSession().createQuery("from User").list();}}事务隔离级别spring⾥⾯事务的传播属性和事务隔离级别。
spring事务传播机制和隔离级别

Spring事务传播机制与隔离级别一、spring支持7种事务传播行为1、propagation_required(xml文件中为required)当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。
(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)。
2、propagation_supports(xml文件中为supports)当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行。
3、propagation_mandatory(xml文件中为mandatory)表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常。
4、propagation_nested(xml文件中为nested)如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。
如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。
如果封装事务不存在,则同propagation_required的一样。
5、propagation_never(xml文件中为never)当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常。
6、propagation_requires_new(xml文件中为requires_new)当前方法必须运行在它自己的事务中。
一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。
7、propagation_not_supported(xml文件中为not_supported)方法不应该在一个事务中运行。
如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行。
二、spring中的事务隔离级别1、isolation_default使用数据库默认的事务隔离级别。