Spring-七种事务传播特性
作者:互联网
以下面2个方法为例:
@Service
public class DaoService {
@Transactional
public void laoda() {
System.out.println("老大的方法");
//在老大方法里面调用小弟方法
xiaodi();
}
@Transactional
public void xiaodi() {
System.out.println("小弟的方法");
}
}
Spring总共给了7种事务的传播特性:
就是多个事务方法相互调用时,事务如何在这些方法间传播
问题:什么叫传播特性, 拿上面两个方法来说,老大方法调用小弟方法,老大方法里面发生异常小弟事务怎么处理?
分三类:
1.=死活不要事务===
1) PROPAGATION_NEVER: 没有就非事务执行,有就抛异常
eg: 老大调用小弟方法,小弟不允许有事务,当小弟发现老大有事务时,直接抛异常,我不干,没有就正常运行
2) PROPAGATION_NOT_SUPPORTED: 没有就非事务执行,有就直接挂起,然后非事务执行
eg: 老大调用小弟方法,小弟不允许有事务,当小弟发现老大有事务时,就将老大的事务挂起,换句话说就是老大的事务管不着小弟,小弟自己非事务运行,不受老大事务约束
2.=事务可有可无==
3). PROPAGATION_SUPPORTS: 如果有事务就用,没有就非事务执行
eg: 老大调用小弟方法,小弟会去看下老大是否有事务,有就用,没有就算了,非事务运行
3.=必须有事务的==
4).PROPAGATION_REQUIRED_NEW: 有没有都会新建事务,如果原来有,就将原来的挂起;
eg: 老大调用小弟方法,小弟方法必须要有事务,它会去看下老大有没有事务,老大有就将老大的挂起,反正不会用老大的事务,自己新建一个新的。小弟由于是一个新的事务,所以不受老大事务影响,但是如果小弟抛异常,小弟回滚,老大就要看下是否处理异常,没有处理也回滚,处理了就不会回滚
启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。
1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。
2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try…catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
5). PROPAGATION_NESTED: 如果没有,就新建一个事务,如果有,就在当前事务中嵌套其他事务;
eg:老大调用小弟方法,小弟方法必须要有事务,它会去看下老大有没有事务,有就用老大的事务,没有就自己新建一个事务,嵌套其中。当小弟发生异常,会回滚到回滚点 savepoint.,也就是嵌套事务点,外界事务此时不会回滚,除非他对异常没有进行处理,但是如果老大发生异常,由于是嵌套,小弟必然回滚。
开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.
比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_NESTED,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的子事务并设置savepoint,等待ServiceB.methodB的事务完成以后,他才继续执行。。因为ServiceB.methodB是外部事务的子事务,那么
1、如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB也将回滚。
2、如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA的try…catch捕获并处理,ServiceA.methodA事务仍然可能提交;如果他抛出的异常未被ServiceA.methodA捕获处理,ServiceA.methodA事务将回滚。
理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是:
PROPAGATION_REQUIRES_NEW 完全是一个新的事务,它与外部事务相互独立; 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.
在 spring 中使用 PROPAGATION_NESTED的前提:
- 我们要设置 transactionManager 的 nestedTransactionAllowed 属性为 true, 注意, 此属性默认为 false!!!
- java.sql.Savepoint 必须存在, 即 jdk 版本要 1.4+
- Connection.getMetaData().supportsSavepoints() 必须为 true, 即 jdbc drive 必须支持 JDBC 3.0
6) PROPAGATION_REQUIRED: 如果没有,就新建一个事务,如果有,就加入当前事务.
eg:老大调用小弟方法,小弟方法必须要有事务,它会去看下老大有没有事务,有就用老大的事务,没有就自己新建一个事务。 如果老大有事务,此时小弟使用老大事务,他们是一个整体,要么同时成功,要么同时失败,但是如果老大没有事务,小弟自己新建了一个事务,那么即使小弟事务抛异常也不会影响老大,因为老大没事务.
7). PROPAGATION_MANDTORY: 如果没有就抛异常,如果有就是使用当前事务
eg:老大调用小弟方法,小弟方法必须要有事务,它会去看下老大有没有事务,有就用老大的事务,没有就抛异常,反正自己不会去新建事务。
必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常
标签:事务,七种,老大,Spring,小弟,PROPAGATION,methodB,ServiceB 来源: https://blog.csdn.net/Hmj050117/article/details/112690078