spring 在TransactionDefinition.class
中定义了事务的传播属性。并定义了枚举类Propagation.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package org.springframework.transaction.annotation;
public enum Propagation {
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
NEVER(TransactionDefinition.PROPAGATION_NEVER),
NESTED(TransactionDefinition.PROPAGATION_NESTED); private final int value; Propagation(int value) { this.value = value; } public int value() { return this.value; } }
|
spring事务传播示例
- PROPAGATION_REQUIRED
如果当前已经存在事务,那么加入该事务,如果不存在事务,创建一个事务,这是默认的传播属性值。
1 2 3 4 5 6 7 8 9 10 11
| @Transactional public void service() { serviceA(); serviceB(); }
@Transactional public void serviceA() {}
@Transactional public void serviceB() {}
|
service、serviceA、serviceB都声明了事务,没有指定传播机制,默认为PROPAGATION_REQUIRED
,三个方法都在一个事务内,
当三个方法中任意一个出现异常RuntimeException.class
,整个事务都会回滚。
- PROPAGATION_SUPPORTS
如果当前已经存在事务,那么加入该事务,否则就以非事务方式执行。
1 2 3 4 5 6 7
| public void service() { serviceA(); 1/0; }
@Transactional(propagation = Propagation.SUPPORTS) public void serviceA() {}
|
service没有开启事务,serviceA在无事务下执行完成。此时serviceA不会回滚。
1 2 3 4 5 6 7 8 9 10 11
| @Transactional public void service() { serviceA(); }
@Transactional(propagation = Propagation.SUPPORTS) public void serviceA() { exe sql1; int i = 1/0; exe sql2; }
|
service没有开启事务,serviceA在无事务下执行完成。
我测试的时候,sql1不会回滚。因为使用了druid数据源,默认defaultAutoCommit = true;
- PROPAGATION_MANDATORY
使用当前的事务,如果当前没有事务,就抛出异常。
1 2 3 4 5 6 7 8 9
| public void service() { serviceA(); serviceB(); }
public void serviceA() {}
@Transactional(propagation = Propagation.MANDATORY) public void serviceB() {}
|
serviceA执行成功,serviceB将会抛出异常
- PROPAGATION_REQUIRES_NEW
新建事务,如果当前存在事务,把当前事务挂起。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Transactional public void service(){ serviceA(); try { serviceB(); } catch (Exception e) { } } serviceA() {}
@Transactional(propagation=Propagation.REQUIRES_NEW) serviceB() { do sql 1 1/0; do sql 2 }
|
当调用service接口时,由于serviceB使用的是REQUIRES_NEW,它会创建一个新的事务,
但由于serviceB抛出了运行时异常,导致serviceB整个被回滚了,而在service方法中,捕获了异常,所以serviceA是正常提交的。
注意,service中的try-catch
代码是必须的,否则service也会抛出异常,导致serviceA也被回滚。
- PROPAGATION_NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Transactional public void service() { serviceA(); serviceB(); } serviceA(){ exe sql } @Transactional(propagation=Propagation.NOT_SUPPORTED) serviceB() { exe sql 1 int i = 1/0; exe sql 2 }
|
当调用service方法的时候,执行到serviceB方法中的1/0代码时,抛出了异常,
由于serviceB处于无事务环境下,所以 sql1是否生效取决于defaultAutoCommit的值,
当defaultAutoCommit=true时,sql1是生效的。但是service由于抛出了异常,所以serviceA会被回滚。
- PROPAGATION_NEVER
以非事务方式执行,如果当前存在事务,则抛出异常。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void service() { serviceA(); serviceB(); } serviceA(){ exe sql } @Transactional(propagation=Propagation.NEVER) serviceB() { exe sql 1 1/0; exe sql 2 }
|
serviceA会执行成功,若defaultAutoCommit=true,则serviceB中的sql1会生效。
- PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Transactional public void service() { serviceA(); try { serviceB(); } catch (Exception e) { } } serviceA() { exe sql } @Transactional(propagation=Propagation.NESTED) serviceB() { exe sql1 int i = 1/0; exe sql2 }
|
serviceB是一个内嵌的业务,内部抛出了运行时异常,所以serviceB整个被回滚了,由于service捕获了异常,所以serviceA是可以正常提交的。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Transactional public void service() { serviceA(); serviceB(); int i = 1/0; } @Transactional(propagation=Propagation.NESTED) serviceA() { exe sql } serviceB() { exe sql }
|
由于service抛出了异常,所以会导致整个service方法被回滚。(这就是跟PROPAGATION_REQUIRES_NEW不一样的地方了,NESTED方式下的内嵌业务会受到外部事务的异常而回滚。)
坑
参考
https://blog.csdn.net/yanyan19880509/article/details/53041564