Spring的@Transactional注解属性优先级/继承
Spring的@Transactional注解属性优先级/继承
在调用者方法本身已经是事务性的情况下,当传播行为设置为REQUIRED
时,如果当前方法与包含它的事务属性不同,那么当前方法是否会覆盖它们(例如rollbackFor)?
说明:
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() { [...] } }
编辑:
好的,我想避免显而易见的超出范围的答案,所以让我们清楚一点,我知道spring处理传播行为。
如果您不知道,请参阅文档的下面部分,我只想澄清上面我例子中第一部分的内容:
PROPAGATION_REQUIRED
当传播设置为PROPAGATION_REQUIRED时,对于每个应用设置该设置的方法,都将创建一个逻辑性事务范围。每个这样的逻辑性事务范围可以单独确定仅回滚状态,外部事务范围在逻辑上独立于内部事务范围。当然,在标准PROPAGATION_REQUIRED行为的情况下,所有这些范围都将映射到同一个物理事务。因此,在内部事务范围设置回滚唯一标记的情况下,外部事务尚未决定回滚自身,因此在内部事务范围默默触发回滚(您期望的方式),预计会发生回滚。在此时抛出相应的UnexpectedRollbackException异常。这是预期的行为,以便一个事务的调用者永远不会被误导以为已执行提交,而实际上并没有。因此,如果内部事务(外部调用者不知道其存在)默默将事务标记为仅回滚,那么外部调用者仍然会调用提交。外部调用者需要接收UnexpectedRollbackException以明确指示已执行回滚。
我的问题可以重新表述为:逻辑事务范围是否包含事务属性?
根据我的理解,我会在这个例子中说:
Class A { @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { SomeException.class}) void foo() { try { b.bar(); } catch (OtherException e) { // the transaction is marked as rollback-only by the inner call as it thrown an OtherException // XXX --- or not if inner logical scope does not handle overridden property 'rollbackFor' ? --- // anyway, we avoid UnexpectedRollbackException by enforcing physical rollback to outter scope programmatically, by throwing : throw new SomeExeption(e); } } } Class B { @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { OtherException.class}) void bar() { [...] } }
因此,我们可以将问题重述为:覆盖的 "rollbackFor" 属性是否由内部逻辑事务范围管理处理?
顺便问一下,你使用的确切事务管理器类和版本是什么?
因此,我设置了一个测试案例,简短的答案是是。
事务逻辑范围保存了事务属性,它的边界确实是被标注方法的边界。
因此,即使底层物理事务对两个方法都是相同的,逻辑属性对于每个方法是不同的,内部方法可以强制回滚外部方法的事务。
但如果这最后触发了提交,它将导致一个UnexpectedRollbackException。
参见Spring TransactionInterceptor(注释是我的)
try { retVal = invocation.proceed(); } catch (Throwable ex) { completeTransactionAfterThrowing(txInfo, ex); throw ex; }
completeTransactionAfterThrowing():
// txinfo is proper to the invocation target method if (txInfo.transactionAttribute.rollbackOn(ex)) { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); }
AbstractPlatformTransactionManager.processRollback():
else if (status.isNewTransaction()) { //requiresnew doRollback(status); } else if (status.hasTransaction()) { //requiered [...] doSetRollbackOnly(status); } }