【转载】Spring 中,事务的传播方式

1,864 total views, 12 views today

转载自 https://blog.csdn.net/pml18710973036/article/details/58607148

Spring 事务传播行为:

spring 特有的事务传播行为,spring 支持 7 种事务传播行为,确定客户端和被调用端的事务边界(说得通俗一点就是多个具有事务控制的 service 的相互调用时所形成的复杂的事务边界控制)下图所示为 7 钟事务传播机制

o

传播行为

含义

PROPAGATION_REQUIRED(XML 文件中为 REQUIRED)

表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)

PROPAGATION_SUPPORTS(XML 文件中为 SUPPORTS)

表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行

PROPAGATION_MANDATORY(XML 文件中为 MANDATORY)

表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常

PROPAGATION_NESTED(XML 文件中为 NESTED)

表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同 PROPAGATION_REQUIRED 的一样

PROPAGATION_NEVER(XML 文件中为 NEVER)

表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常

PROPAGATION_REQUIRES_NEW(XML 文件中为 REQUIRES_NEW)

表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

PROPAGATION_NOT_SUPPORTED(XML 文件中为 NOT_SUPPORTED)

表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行

 

例子讲解以上七中事务传播机制

假设有类 A 的方法 methodB(), 有类 B 的方法 methodB().

1)     PROPAGATION_REQUIRED

如果 B 的方法 methodB() 的事务传播特性是 propagation_required,那么如下图

A.methodA() 调用 B 的 methodB() 方法,那么如果 A 的方法包含事务,则 B 的方法则不从新开启事务,

1、  如果 B 的 methodB() 抛出异常,A 的 methodB() 没有捕获,则 A 和 B 的事务都会回滚;

2、    如果 B 的 methodB() 运行期间异常会导致 B 的 methodB() 的回滚,A 如果捕获了异常,并正常提交事务,则会发生 Transaction rolled back because it has been marked as rollback-only 的异常。

3、  如果 A 的 methodA() 运行期间异常,则 A 和 B 的 Method 的事务都会被回滚

 

 

2)     PROPAGATION_SUPPORTS

如果 B 的方法 methodB() 的事务传播特性是 propagation_supports, 么如下图

A.methodA() 调用 B 的 methodB() 方法,那么如果 A 的方法包含事务,则 B 运行在此事务环境中,如果 A 的方法不包含事务,则 B 运行在非事务环境;

1、如果 A 没有事务,则 A 和 B 的运行出现异常都不会回滚。

2、如果 A 有事务,A 的 method 方法执行抛出异常,B.methodB 和 A.methodA 都会回滚。

3、如果 A 有事务,B.method 抛出异常,B.methodB 和 A.methodA 都会回滚,如果 A 捕获了 B.method 抛出的异常,则会出现异常 Transactionrolled back because it has been marked as rollback-only。

 

3)     PROPAGATION_MANDATORY

表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常,如下图调用关系:

B.methodB() 事务传播特性定义为:PROPAGATION_MANDATORY

1、如果 A 的 methoda() 方法没有事务运行环境,则 B 的 methodB() 执行的时候会报如下异常:No existingtransaction found for transaction marked with propagation ‘mandatory’

2、如果 A 的 Methoda() 方法有事务并且执行过程中抛出异常,则 A.methoda()和 B.methodb()执行的操作被回滚;

3、如果 A 的 methoda() 方法有事务,则 B.methodB() 抛出异常时,A 的 methoda() 和 B.methodB() 都会被回滚;如果 A 捕获了 B.method 抛出的异常,则会出现异常 Transaction rolled back because ithas been marked as rollback-only

 

 

4)     PROPAGATION_NESTED

如有一下方法调用关系,如图:

B 的 methodB() 定义的事务为 PROPAGATION_NESTED;

1、        如果 A 的 MethodA() 不存在事务,则 B 的 methodB() 运行在一个新的事务中,B.method() 抛出的异常,B.methodB() 回滚, 但 A.methodA() 不回滚;如果 A.methoda() 抛出异常,则 A.methodA() 和 B.methodB() 操作不回。

2、        如果 A 的 methodA() 存在事务,则 A 的 methoda() 抛出异常,则 A 的 methoda() 和 B 的 Methodb() 都会被回滚;

3、        如果 A 的 MethodA() 存在事务,则 B 的 methodB() 抛出异常,B.methodB() 回滚,如果 A 不捕获异常,则 A.methodA() 和 B.methodB() 都会回滚,如果 A 捕获异常,则 B.methodB() 回滚,A 不回滚;

5)PROPAGATION_NEVER

表示事务传播特性定义为 PROPAGATION_NEVER 的方法不应该运行在一个事务环境中

有如下调用关系:

 

如果 B.methodB() 的事务传播特性被定义为 PROPAGATION_NEVER,则如果 A.methodA() 方法存在事务,则会出现异常 Existingtransaction found for transaction marked with propagation ‘never’。

6)PROPAGATION_REQUIRES_NEW

表示事务传播特性定义为 PROPAGATION_REQUIRES_NEW 的方法需要运行在一个新的事务中。

如有一下调用关系:B.methodB() 事务传播特性为 PROPAGATION_REQUIRES_NEW.

1、        如果 A 存在事务,A.methodA() 抛出异常,A.methodA() 的事务被回滚,但 B.methodB() 事务不受影响;如果 B.methodB() 抛出异常,A 不捕获的话,A.methodA() 和 B.methodB() 的事务都会被回滚。如果 A 捕获的话,A.methodA() 的事务不受影响但 B.methodB() 的事务回滚。

7) PROPAGATION_NOT_SUPPORTED

表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行。

如有一下调用关系图:

如果 B.methodB() 方法传播特性被定义为:PROPAGATION_NOT_SUPPORTED。

1、        如果 A.methodA() 存在事务,如果 B.methodB() 抛出异常,A.methodA() 不捕获的话,A.methodA() 的事务被回滚,而 B.methodB() 出现异常前数据库操作不受影响。如果 A.methodA() 捕获的话,则 A.methodA() 的事务不受影响,B.methodB() 异常抛出前的数据操作不受影响。

 

实际场景中的七大事务传播行为的使用

1、  在一个话费充值业务处理逻辑中,有如下图所示操作:

业务需要扣款操作和创建订单操作同成功或者失败,因此,charger() 和 order() 的事务不能相互独立,需要包含在 chargeHandle() 的事务中;

通过以上需求,可以给 charge() 和 order() 的事务传播行为定义成:PROPAGATION_MANDATORY

只要 charge() 或者 order() 抛出异常整个 chargeHandle() 都一起回滚,即使 chargeHandle() 捕获异常也没用,不允许提交事务。

2、  如果业务需求没接受到一次请求到要记录日志到数据库,如下图:

因为 log() 的操作不管扣款和创建订单成功与否都要生成日志,并且日志的操作成功与否不影响充值处理,所以 log() 方法的事务传播行为可以定义为:PROPAGATION_REQUIRES_NEW.

3、  在订单的售后处理中,更新完订单金额后,需要自动统计销售报表,如下图所示:

根据业务可知,售后是已经处理完订单的充值请求后的功能,是对订单的后续管理,统计报表 report() 方法耗时较长,因此,我们需要设置 report() 的事务传播行为为:PROPAGATION_NEVER, 表示不适合在有事务的操作中调用,因为 report() 太耗时。

4、  在银行新增银行卡业务中,需要执行两个操作,一个是保存银行卡信息,一个是登记新创建的银行卡信息,其中登记银行卡信息成功与否不影响银行卡的创建。

由以上需求,我们可知对于 regster() 方法的事务传播行为,可以设置为 PROPAGATION_NESTED,action() 事务的回滚,regster() 保存的信息就没意义,也就需要跟着回滚,而 regster() 的回滚不影响 action() 事务;insert() 的事务传播行为可以设置为 PROPAGATION_REQUIRED, PROPAGATION_MANDATORY,即 insert() 回滚事务,action() 的事务必须跟着回滚。

转载自 https://blog.csdn.net/pml18710973036/article/details/58607148

原创文章,转载请注明出处!http://www.javathings.top/【转载】spring中,事务的传播方式/

About: wusq


发表评论

邮箱地址不会被公开。 必填项已用*标注