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