Spring事务的七种传播行为
首先举例事务的嵌套:
ServiceA {
void methodA() {
ServiceB.methodB();
}
}
ServiceB {
void methodB() {
}
}
其中ServiceA#methodA(我们称之为外部事务),ServiceB#methodB(我们称之为内部事务)
一、PROPAGATION_REQUIRED(Spring默认,常用)
如果当前要执行的事务不在另外一个事务中,那么就新起一个事务。比如ServiceB.methodB的事务级别 定义为PROPAGATION_REQUIRED,那么当执行ServiceA.methodA的时候有两种情况:
- 如果ServiceA.methodA已经存在事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA的事务内部,就不再起新的事务。这时只有外部事务并且他们是共用的,所以这时ServiceA.methodA或者ServiceB.methodB无论哪个发生异常methodA和methodB作为一个整体都将一起回滚。
- 如果ServiceA.methodA没有事务,ServiceB.methodB就会为自己分配一个事务。这样,在ServiceA.methodA中是没有事务控制的。只是在ServiceB.methodB内的任何地方出现异常,ServiceB.methodB将会被回滚,不会引起ServiceA.methodA的回滚。
二、PROPAGATION_REQUIRES_NEW(常用)
启动一个新的,不依赖于环境的 "内部" 事务。 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务,它拥有自己的隔离范围,自己的锁,等等。当内部事务开始执行时,外部事务将被挂起,内务事务结束后,外部事务才将继续执行。
比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务:
- 如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。
- 如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
三、PROPAGATION_NESTED(常用)
开始一个"嵌套的"事务,它是已经存在事务的一个真正的子事务。嵌套事务开始执行时,它将取得一个 savepoint。如果这个嵌套事务失败,我们将回滚到此savepoint。潜套事务是外部事务的一部分,只有外部事务结束后它才会被提交。
比如我们将ServiceA.methodA事务级别设置为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_NESTED,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的子事务并设置savepoint,等待ServiceB.methodB的事务完成以后,ServiceA.methodA的事务才继续执行。因为ServiceB.methodB是外部事务的子事务,那么
- ServiceB.methodB执行完成无异常,此时还未提交事务,如果ServiceA.methodA发生异常回滚,ServiceB.methodB也将回滚。
- 如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try..catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
他与PROPAGATION_REQUIRES_NEW的区别是:
PROPAGATION_REQUIRES_NEW完全是一个新事务它与外部事务相互独立,而 PROPAGATION_NESTED 则是外部事务的子事务,如果外部事务 commit, 嵌套事务也会被 commit,这个规则同样适用于 roll back。
在Spring中使用PROPAGATION_NESTED的前提条件:
- TransactionManager中的nestedTransactionAllowed属性必须是true;
- JKD版本为1.4+,因为需要SavePoint类;
- JDBC Driver必须支持JDBC3.0。
四、PROPAGATION_SUPPORTS
如果当前运行的代码包含在事务中,就以事务的方式运行,如果不在一个事务中,就以非事务的方式运行。
五、PROPAGATION_NOT_SUPPORTED
表示当前不支持事务。例如传播属性为PROPAGATION_REQUIRED的外部事务ServiceA.methodA,而ServiceB.methodB为内部事务,它的传播属性为PROPAGATION_NOT_SUPPORTED,当运行到ServiceB.methodB的时候ServiceA.methodA的事务将被挂起,待ServiceB.methodB以非事务的方式运行完以后,再来执行ServiceA.methodA的事务。
六、PROPAGATION_MANDATORY
必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常。
七、PROPAGATION_NEVER
不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,那么ServiceB.methodB就要抛出异常了。
标签:事务,ServiceB,ServiceA,methodA,传播,PROPAGATION,methodB,Spring From: https://www.cnblogs.com/zhangjianbing/p/17582554.html