`

Spring事务传播机制

阅读更多
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 事务传播机制是指在 Spring 框架中,事务的传播和嵌套机制。当我们在使用 Spring 所提供的事务功能时,如果是仅仅处理单个的事务,是比较容易把握事务的提交与回滚,不过一旦引入嵌套...

    spring 事务传播 demo

    本示例“spring 事务传播 demo”将聚焦于Spring的事务传播行为,这是在多个方法调用中控制事务边界的关键概念。下面我们将详细讨论相关知识点。 首先,事务传播行为是指当一个被@Transactional注解的方法被另一个@...

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

    Spring提供了七种事务传播特性,每一种都有其特定的场景适用性。 1. **PROPAGATION_REQUIRED** - 这是最常用的传播行为。当使用此传播行为时,如果当前存在事务,则在该事务中执行;如果没有,则创建一个新的事务...

    spring事物隔离和传播机制

    #### 一、Spring 事务传播机制 Spring 的事务管理功能非常强大,其中一个重要特性就是事务传播行为。事务传播行为定义了当一个方法调用另一个方法时,如何处理事务边界的问题。Spring 提供了七种不同的传播行为: ...

    spring 事务传播

    通过上述对Spring事务传播行为的详细介绍,我们可以看出,正确理解和应用这些传播行为对于构建健壮的事务管理机制至关重要。每种传播行为都有其特定的应用场景和限制条件,开发者应根据具体的业务逻辑和需求来合理...

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

    ### Spring事务的七大传播行为 ...总结来说,选择合适的事务传播行为和隔离级别对于确保应用程序的数据一致性至关重要。开发者需要根据业务需求权衡性能和数据一致性之间的关系,以选择最合适的设置。

    浅谈Spring事务传播行为实战

    二、Spring事务传播机制: 1. REQUIRED:如果当前事务存在,则加入当前事务,如果当前事务不存在,则创建一个新的事务。 2. REQUIRES_NEW:总是创建一个新的事务,如果当前事务存在,则挂起当前事务。 3. SUPPORTS...

    深入理解spring的事务管理机制

    Spring事务管理的核心是基于AOP(面向切面编程)来实现的。 **Spring事务的本质**实际上是依赖于底层数据库提供的事务支持。如果没有数据库层面的支持,Spring无法单独实现事务的功能。在传统的JDBC操作中,如果想...

    spring 事务传播与隔离级别DEMO

    本DEMO主要探讨的是Spring事务的传播行为和隔离级别,这些概念对于理解和优化数据库操作至关重要。让我们深入理解这些概念及其实际应用。 首先,我们来谈谈事务的传播行为。在Spring中,当一个方法被另一个具有事务...

    Spring框架+Spring中的事务

    #### 三、Spring事务传播机制详解 **1. 事务传播机制的概念** 事务传播机制是指在多个事务操作发生时,如何管理这些操作之间的事务关系。在Spring框架中,可以通过`org.springframework.transaction.annotation....

    Spring事务传播属性

    Spring事务传播属性是这一机制的关键组成部分,它定义了在一个事务方法被另一个事务方法调用时,应该如何处理事务的边界。在深入理解Spring事务传播属性之前,我们首先需要了解Spring中的事务管理模型,包括编程式...

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

    Spring事务传播属性和隔離级别详细介绍 Spring事务传播属性(Propagation)是指在事务中如何...Spring事务传播属性和隔离级别是对事务进行管理和控制的重要机制,可以帮助开发者更好地管理事务,避免各种并发问题。

    Spring事务传播原理及数据库事务操作原理.rar

    总的来说,Spring事务传播原理和数据库事务操作原理是Java开发人员必须掌握的核心知识。理解这些原理,能够帮助我们在开发过程中更好地处理数据一致性问题,保证系统的稳定性和可靠性。通过对Spring事务机制的熟练...

    spring事物传播测试表

    事务传播行为(Transaction Propagation)是Spring事务管理中一个关键的概念,用于定义在一个事务方法被调用时,如何与当前运行的事务进行交互。本文将深入探讨“Spring事物传播测试表”所涉及的知识点。 首先,...

    spring事务与数据库操作

    ### Spring事务与数据库操作 #### 一、Spring的声明式事务管理 在现代软件开发中,事务处理是非常关键的一部分,特别是在涉及多个数据操作时。Spring框架提供了强大的事务管理能力,可以方便地集成到应用程序中。...

    Spring事务管理失效原因汇总

    在讨论了代理模式、异常分类、方法权限后,文章还提到了Spring事务管理中事务的传播机制和隔离机制。事务的传播机制定义了事务的行为,例如是否在当前事务中执行或者创建一个新的事务。隔离机制定义了事务之间的隔离...

    sourcecode.zip

    总的来说,"sourcecode.zip"提供了学习和实践Spring事务传播机制的宝贵资源。通过对源码的阅读和测试用例的执行,你可以深入理解Spring事务管理的核心原理,并将这些知识应用到实际项目中,提升开发效率和软件质量。

    spring常用数据库事务传播属性和事务隔离级别1

    Spring 框架提供了一套完善的事务管理机制,其中包含了多种事务传播属性和事务隔离级别。这些特性使得在处理数据库操作时,能够更好地控制事务的边界和行为,从而确保数据的一致性和完整性。 首先,我们来看一下...

    spring事务管理机制资料.zip

    Spring还提供了事务传播行为,定义了在一个事务方法被另一个事务方法调用时应该如何处理事务。例如,PROPAGATION_REQUIRED表示如果当前没有事务,就新建一个;PROPAGATION_SUPPORTS表示如果存在事务则加入,否则无需...

Global site tag (gtag.js) - Google Analytics