关于spring事务传播特性的相关问题的解释
程序员文章站
2022-06-07 12:58:34
...
昨天帮助同事解决一个问题,其中遇到一个问题涉及到spring的事务,当时有点不敢肯定,做了实验,并参考了其他同仁的,做了些总结,希望能帮助到大家。
我们首先先来看下spring的事务的传播特性:
事务传播行为类型 |
说明 |
PROPAGATION_REQUIRED |
如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS |
支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY |
使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW |
新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED |
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER |
以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED |
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,并且实现者需要支持保存点事务机制。
我们现在挨个来讲解下这个里面容易误解的几个:
1. PROPAGATION_REQUIRED
假设有下面代码:
ServiceA { /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodA() { try { ServiceB.methodB(); } catch(Exception e){ e.printstacktrace(); } } } ServiceB { /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodB() { } }
其实required从我面试候选人来看,基本上都能答出来,但是看到上面的情景是回滚还是提交,基本上答上来的很少,我们再来看下定义,如果当前没有事务,就开启一个,如果有就加入到这个事务里面,也就是说整个是一个事务,所以B发生异常,会导致整个事务一块回滚。从这个里面可以看到,简单的将methodB异常捕获,认为整个事务会提交,其实是不行的。
2. PROPAGATION_REQUIRES_NEW
ServiceA { /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodA() { try { ServiceB.methodB(); } catch(Exception e){ e.printstacktrace(); } } } ServiceB { /** * 事务属性配置为 PROPAGATION_REQUIRES_NEW */ void methodB() { } }requires new这种类型,基本上所有的人都能答正确,A和B是两个独立的事务,内外两个事务没有任何影响,结果是B回滚,A提交
3. PROPAGATION_REQUIRED
ServiceA { /** * 事务属性配置为 PROPAGATION_REQUIRED */ void methodA() { try { ServiceB.methodB(); } catch(Exception e){ e.printstacktrace(); } } } ServiceB { /** * 事务属性配置为 PROPAGATION_NESTED */ void methodB() { } }
从概念来看,有一个嵌套事务出现了
我们来分析下这个,首先我们先根据一个图将这个分解下:
(上图A、B、C、D代表几个时机,我们用AD和BC代表这两个事务,1,2,3代表事务执行的三个阶段)
嵌套事务达到的效果如下:
1. 事务BC与事务AD一起commit,即:作为事务AD的子事务,事务BC只有在事务AD成功commit时(阶段3成功)才commit。这个需求简单称之为“联合成功”
2. 事务BC的rollback不影响事务AD的commit
也就是说第一个是required的特性,第二个是requires new的特性
当BC事务成功commit时,PROPAGATION_NESTED的行为与PROPAGATION_REQUIRED一样。只有当事务AD在D点成功commit时,事务BC才真正commit,如果阶段3执行异常,导致事务AD rollback,事务BC也将一起rollback ,从而满足了“联合成功”
当阶段2执行异常,导致BC事务rollback时,因为设置了savePoint,AD事务可以选择与BC一起rollback或继续阶段3的执行并保留阶段1的执行结果,从而满足了“隔离失败”。
强调,补充一点:PROPAGATION_NESTED只是Spring针对JDBC3.0以上版本SavePoint机制的一个事务传播机制的扩展,J2EE体系中是没有的,所以如果应用中使用JTA作为底层的事务管理机制的话,使用Spring也是不可能支持PROPAGATION_NESTED。
下一篇: 豆瓣250评分排名算法机制