Spring事务传播机制
在 spring的 TransactionDefinition接口中一共定义了7种事务传播属性:
PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是spring事务传播机制的默认值。
PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED – 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
加上不加事务,我们总共有8种选择。
下面做了一点测试,写了2个简单的service,来测试事务的传播机制,methodA分别遍历上面8种case,methodB同理,那么我们总共有64种选择。当然,除了这64种,还有需要讨论的。
- A在B insert后抛异常 这是我们要分析的,是否抛异常有2种可能。
- B在insert后抛异常 此时B会回滚。A是否回滚需要看methodA在调用methodB时是否加try-catch了。如果加了,A就不会回滚,这里就不做讨论了。如果不加,不管A选择的是哪种机制,都会回滚(因为throw exception了),这里也不作讨论。
所以,我们要跑的case有2*64=128种,上面的64种加上A在调用B后是否抛异常。
ServiceA {
//注解
void methodA() {
insertDB();
ServiceB.methodB();
//这里抛异常或者不抛
}
}
ServiceB {
//注解
void methodB() {
insertDB();
}
}
注:下面空白表示AB都执行了,B回滚表示B可能真的回滚了,也可能表示B根本就没往数据库插数据。
不抛异常的情况下
methodA\methodB | 无事务 | REQUIRED | SUPPORTS | MANDATORY | REQUIRES_NEW | NOT_SUPPORTED | NEVER | NESTED |
---|---|---|---|---|---|---|---|---|
无事务 | A写入,B回滚 | |||||||
REQUIRED | A回滚、B回滚 | |||||||
SUPPORTS | A写入、B回滚 | |||||||
MANDATORY | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | |
REQUIRES_NEW | A回滚、B回滚 | |||||||
NOT_SUPPORTED | A写入、B回滚 | |||||||
NEVER | A写入、B回滚 | |||||||
NESTED | A回滚B回滚 |
抛异常的情况下
methodA\methodB | 无事务 | REQUIRED | SUPPORTS | MANDATORY | REQUIRES_NEW | NOT_SUPPORTED | NeVER | NESTED |
---|---|---|---|---|---|---|---|---|
无事务 | A写入,B回滚 | |||||||
REQUIRED | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B写入 | A回滚、B写入 | A回滚、B回滚 | A回滚、B回滚 |
SUPPORTS | A写入、B回滚 | |||||||
MANDATORY | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 |
REQUIRES_NEW | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B写入 | A回滚、B写入 | A回滚、B回滚 | A回滚、B回滚 |
NOT_SUPPORTED | A写入、B回滚 | |||||||
NeVER | A写入、B回滚 | |||||||
NeVER | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B回滚 | A回滚、B写入 | A回滚、B写入 | A回滚、B回滚 | A回滚、B回滚 |