`

Spring事务传播机制

阅读更多
概述
           
当我们调用一个基于Spring的Service接口方法(如UserService#addUser())时,它将运行于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,并且实现者需要支持保存点事务机制。
           
几种容易引起误解的组合事务传播行为
           
当服务接口方法分别使用表1中不同的事务传播行为,且这些接口方法又发生相互调用的情况下,大部分组合都是一目了然,容易理解的。但是,也存在一些容易引起误解的组合事务传播方式。
           
下面,我们通过两个具体的服务接口的组合调用行为来破解这一难点。这两个服务接口分别是UserService和ForumService, UserSerice有一个addCredits()方法,ForumSerivce#addTopic()方法调用了 UserSerice#addCredits()方法,发生关联性服务方法的调用:
           
public class ForumService {
           
private UserService userService;
           
public void addTopic(){①调用其它服务接口的方法
           
//add Topic…
           
userService.addCredits();②被关联调用的业务方法
           
}
           
}
           
嵌套调用的事务方法
           
对Spring事务传播行为最常见的一个误解是:当服务接口方法发生嵌套调用时,被调用的服务方法只能声明为 PROPAGATION_NESTED。这种观点犯了望文生义的错误,误认为PROPAGATION_NESTED是专为方法嵌套准备的。这种误解遗害不 浅,执有这种误解的开发者错误地认为:应尽量不让Service类的业务方法发生相互的调用,Service类只能调用DAO层的DAO类,以避免产生嵌 套事务。
           
其实,这种顾虑是完全没有必要的,PROPAGATION_REQUIRED已经清楚地告诉我们:事务的方法会足够“聪明”地判断上下文是否已经存在一个事务中,如果已经存在,就加入到这个事务中,否则创建一个新的事务。
           
依照上面的例子,假设我们将ForumService#addTopic()和UserSerice#addCredits()方法的事务传播行为都设置为PROPAGATION_REQUIRED,这两个方法将运行于同一个事务中。
           
为了清楚地说明这点,可以将Log4J的日志设置为DEBUG级别,以观察Spring事务管理器内部的运行情况。下面将两个业务方法都设置为PROPAGATION_REQUIRED,Spring所输出的日志信息如下:
           
Using transaction object
           
[org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@e3849c]
           
①为ForumService#addTopic()新建一个事务
           
Creating new transaction with name [com.baobaotao.service.ForumService.addTopic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
           
Acquired Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] for JDBC transaction
           
Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] to manual commit
           
Bound value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] to thread [main]
           
Initializing transaction synchronization
           
Getting transaction for [com.baobaotao.service.ForumService.addTopic]
           
Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] bound to thread [main]
           
Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@8b8a47]
           
②UserService#addCredits()简单地加入到已存在的事务中(即①处创建的事务)
           
Participating in existing transaction
           
Getting transaction for [com.baobaotao.service.UserService.addCredits]
           
Completing transaction for [com.baobaotao.service.UserService.addCredits]
           
Completing transaction for [com.baobaotao.service.ForumService.addTopic]
           
Triggering beforeCommit synchronization
           
Triggering beforeCompletion synchronization
           
Initiating transaction commit
           
③调用底层Connection#commit()方法提交事务
           
Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5]
           
Triggering afterCommit synchronization
           
Triggering afterCompletion synchronization
           
Clearing transaction synchronization
           
嵌套事务
           
将ForumService#addTopic()设置为PROPAGATION_REQUIRED时, UserSerice#addCredits()设置为PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、 PROPAGATION_MANDATORY时,运行的效果都是一致的(当然,如果单独调用addCredits()就另当别论了)。
           
当addTopic()运行在一个事务下(如设置为PROPAGATION_REQUIRED),而addCredits()设置为 PROPAGATION_NESTED时,如果底层数据源支持保存点,Spring将为内部的addCredits()方法产生的一个内嵌的事务。如果 addCredits()对应的内嵌事务执行失败,事务将回滚到addCredits()方法执行前的点,并不会将整个事务回滚。内嵌事务是内层事务的一 部分,所以只有外层事务提交时,嵌套事务才能一并提交。
           
嵌套事务不能够提交,它必须通过外层事务来完成提交的动作,外层事务的回滚也会造成内部事务的回滚。
           
嵌套事务和新事务
           
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED也是容易混淆的两个传播行为。PROPAGATION_REQUIRES_NEW 启动一个新的、和外层事务无关的“内部”事务。该事务拥有自己的独立隔离级别和锁,不依赖于外部事务,独立地提交和回滚。当内部事务开始执行时,外部事务 将被挂起,内务事务结束时,外部事务才继续执行。
           
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于:PROPAGATION_REQUIRES_NEW 将创建一个全新的事务,它和外层事务没有任何关系,而 PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务,当外层事务提交或回滚时,子事务也会连带提交和回滚。
           
其它需要注意问题
           
以下几个问题值得注意:
           
1) 当业务方法被设置为PROPAGATION_MANDATORY时,它就不能被非事务的业务方法调用。如将ForumService#addTopic ()设置为PROPAGATION_MANDATORY,如果展现层的Action直接调用addTopic()方法,将引发一个异常。正确的情况是: addTopic()方法必须被另一个带事务的业务方法调用(如ForumService#otherMethod())。所以 PROPAGATION_MANDATORY的方法一般都是被其它业务方法间接调用的。
           
2) 当业务方法被设置为PROPAGATION_NEVER时,它将不能被拥有事务的其它业务方法调用。假设UserService#addCredits ()设置为PROPAGATION_NEVER,当ForumService# addTopic()拥有一个事务时,addCredits()方法将抛出异常。所以PROPAGATION_NEVER方法一般是被直接调用的。
           
3)当方法被设置为PROPAGATION_NOT_SUPPORTED时,外层业务方法的事务会被挂起,当内部方法运行完成后,外层方法的事务重新运行。如果外层方法没有事务,直接运行,不需要做任何其它的事。
           
小结
           
在Spring声明式事务管理的配置中,事务传播行为是最容易被误解的配置项,原因在于事务传播行为名称(如 PROPAGATION_NESTED:嵌套式事务)和代码结构的类似性上(业务类方法嵌套调用另一个业务类方法)。这种误解在很多Spring开发者中 广泛存在,本文深入讲解了Spring事务传播行为对业务方法嵌套调用的真实影响,希望能帮助读者化解对事务传播行为的困惑。
分享到:
评论

相关推荐

    Spring事务传播机制.docx

    spring传播机制个人学习

    spring 事务传播 demo

    spring 事务传播 demo

    spring事务的传播特性和事务隔离级别

    spring事务的传播特性和事务隔离级别

    Spring框架+Spring中的事务

    什么是Spring事务传播机制 Spring事务传播机制是指在多个事务操作发生时,如何管理这些操作之间的事务关系。Spring事务传播机制可以通过Propagation枚举类中的不同值来指定,共包括七种不同的传播行为。具体来说,...

    spring事物的7大传播机制,5个隔离机制

    上文理解到对spring事物,事物的隔离机制,这片具体说下事物的传播机制和隔离机制

    Spring事务传播属性和隔离级别详细介绍

    主要介绍了Spring事务传播属性和隔离级别详细介绍,同时涉及传播行为介绍,超时设置等相关内容,需要的朋友可以参考下。

    spring事务-项目案例-PPT解读.zip

    一、事务传播机制的demo案例,内容包括: 1.业务代码列举7种事务传播机制的情况,每个测试方法都附带日志分析记录、使用场景和实际场景,小白也能看得懂!!! 2.在测试类Test包下,使用juniter进行测试,方便快捷...

    spring事物隔离和传播机制

    对于spring事物的简单理解,对面试或许有帮助,也是加深自己的记忆

    Spring.3.x企业应用开发实战(完整版).part2

    10.3.1 Spring事务传播机制回顾 10.3.2 相互嵌套的服务方法 10.4 多线程的困惑 10.4.1 Spring通过单实例化Bean简化多线程问题 10.4.2 启动独立线程调用事务方法 10.5 联合军种作战的混乱 10.5.1 Spring事务管理器的...

    springTransaction.rar

    里面为一个演示spring事务传播机制的小demo。简单实现转账功能,通过添加注解调整传播级别,同时通过日志打印查看sql是否执行,在mysql中的数据是否发生了变化(操作提交还是回滚了)。

    Spring声明式事务配置管理方法

    可以在spring中对整个项目的事务进行控制

    Spring3.x企业应用开发实战(完整版) part1

    10.3.1 Spring事务传播机制回顾 10.3.2 相互嵌套的服务方法 10.4 多线程的困惑 10.4.1 Spring通过单实例化Bean简化多线程问题 10.4.2 启动独立线程调用事务方法 10.5 联合军种作战的混乱 10.5.1 Spring事务管理器的...

    Spring 事务授课代码

    Spring 事务授课代码 声明式事务 事务传播规则 事务隔离机制

    Spring 事务隔离与事务传播的详解与对比

    Spring 事务隔离与事务传播的详解与对比 Spring是SSH中的管理员,负责管理其它框架,协调各个部分的工作。今天一起学习一下Spring的事务管理。Spring的事务管理分为声明式跟编程式。声明式就是在Spring的配置文件中...

    Spring中的事务传播行为示例详解

    主要给大家介绍了关于Spring中事务传播行为的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

    深入理解Spring声明式事务:源码分析与应用实践

    此外,Spring事务管理器支持多种类型的事务策略,包括不同的传播行为和隔离级别,允许开发者根据具体业务场景选择最合适的事务管理策略。深入理解Spring声明式事务的工作原理,不仅能帮助开发者更高效地使用Spring...

    深入理解Spring的事务传播行为

    spring支持7种事务传播行为,确定客户端和被调用端的事务边界(说得通俗一点就是多个具有事务控制的service的相互调用时所形成的复杂的事务边界控制),这篇文章主要给大家介绍了关于Spring事务传播行为的相关资料,...

    spring-transaction-demo:spring-transaction-demo

    Spring交易演示spring-transaction-demo spring事务传播机制的7种使用方式

    深入理解Spring事务的传播行为

    Spring在TransactionDefinition...下面这篇文章主要给大家介绍了关于Spring事务传播行为的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

Global site tag (gtag.js) - Google Analytics