插图:@H_403_3@
Class A { @Transactional(propagation = Propagation.required,rollbackFor = { SomeException.class}) void foo() { try { b.bar(); } catch (OtherException e) { // is the transaction marked as rollback-only at this point ? } } } Class B { @Transactional(propagation = Propagation.required,rollbackFor = { OtherException.class}) void bar() { [...] } }
编辑:@H_403_3@
好吧,我想避免琐碎的超出范围的答案,所以让我们清楚,我知道弹簧传播处理.@H_403_3@
如果您不是,下面是文档的相关部分,我只想澄清有关上面示例的第一部分:@H_403_3@
When the propagation setting is PROPAGATION_required,a logical
transaction scope is created for each method upon which the setting is
applied. Each such logical transaction scope can determine
rollback-only status individually,with an outer transaction scope
being logically independent from the inner transaction scope. Of
course,in case of standard PROPAGATION_required behavior,all these
scopes will be mapped to the same physical transaction. So a
rollback-only marker set in the inner transaction scope does affect
the outer transaction’s chance to actually commit (as you would expect
it to).@H_403_3@However,in the case where an inner transaction scope sets the
rollback-only marker,the outer transaction has not decided on the
rollback itself,and so the rollback (silently triggered by the inner
transaction scope) is unexpected. A corresponding
UnexpectedRollbackException is thrown at that point. This is expected
behavior so that the caller of a transaction can never be misled to
assume that a commit was performed when it really was not. So if an
inner transaction (of which the outer caller is not aware) silently
marks a transaction as rollback-only,the outer caller still calls
commit. The outer caller needs to receive an
UnexpectedRollbackException to indicate clearly that a rollback was
performed instead.@H_403_3@
我的问题可以改写为:@H_403_3@
解决方法
事务逻辑范围包含事务属性,其边界确实是带注释的方法属性.@H_403_3@
因此,即使两个方法的底层物理事务都相同,逻辑属性也适用于每个方法,而内部方法可以强制回滚外部方法事务.
如果最后一次触发提交,则会导致UnexpectedRollbackException.@H_403_3@
比照Spring TransactionInterceptor(评论是我的)@H_403_3@
try { retVal = invocation.proceed(); } catch (Throwable ex) { completeTransactionAfterThrowing(txInfo,ex); throw ex; }
completeTransactionAfterThrowing():@H_403_3@
// txinfo is proper to the invocation target method if (txInfo.transactionAttribute.rollbackOn(ex)) { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); }
AbstractPlatformTransactionManager.processRollback():@H_403_3@
else if (status.isNewTransaction()) { //requiresnew doRollback(status); } else if (status.hasTransaction()) { //requiered [...] doSetRollbackOnly(status); } }