PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager
PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.
PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行.
另一方面, PROPAGATION_NESTED 开始一个 "嵌套的" 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.
由此可见,
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于,
PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而
PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit,
这个规则同样适用于 roll back.
当然, 就算所有嵌套事务都已经成功, 外部事务还是可能因为嵌套事务的执行结果而导致失败, 此时整个事务都要 roll back ,这也是嵌套事务的重要特性之一, 即外部事务和嵌套事务互相影响
只有需要根据子事务的执行情况进行分支处理的情况下才是nested的用武之地, savepoint是嵌套事务回滚的实现方式 需要注意的是使用它的限制条件
使用嵌套事务是有前提的,就是该嵌套事务可能需要做分支处理。否则用 PROPAGATION_REQUIRED 就足够了,如果子事务有异常,直接回滚。
nested 可以在外层rollback所有内层的事务。requiresnew 不行。
例子:
1. ServiceA {
2.
3. /**
4. * 事务属性配置为 PROPAGATION_REQUIRED
5. */
6. void
7. ServiceB.methodB();
8. }
9.
10. }
11.
12. ServiceB {
13.
14. /**
15. * 事务属性配置为 PROPAGATION_REQUIRES_NEW
16. */
17. void
18. }
19.
20. }
PROPAGATION_REQUIRES_NEW 时 ServiceB.methodB 没办法回滚到它执行之前的 SavePoint, 这时已经产生了一些脏数据, 而这些脏数据将可能导致后面的程序执行出错
1. ServiceA {
2.
3. /**
4. * 事务属性配置为 PROPAGATION_REQUIRED
5. */
6. void
7. try{
8. ServiceB.methodB();
9. }catch(Exeception e){
10. ServiceC.methodC();
11. }
12. }
13.
14. }
15.
16. ServiceB {
17.
18. /**
19. * 事务属性配置为 PROPAGATION_NESTED
20. */
21. void
22. }
23.
24. }
对于PROPAGATION_NESTED 的嵌套事务而言,如果 ServiceB.methodB()异常,会会回滚到上一个savepoint点,外层事务A,可以捕获,处理ServiceC.methodC(),但是对于ServiceA.methodA()异常,会回滚整个嵌套的事务