Spring @Transactional 注解属性优先级/继承
Posted
技术标签:
【中文标题】Spring @Transactional 注解属性优先级/继承【英文标题】:Spring @Transactional Annotation properties precedence / inheritance 【发布时间】:2016-01-21 12:39:39 【问题描述】:在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()
[...]
编辑:
好吧,我想避免琐碎的超出范围的答案,所以让我们明确一点,我知道弹簧传播处理。
如果你不是,下面是文档的相关部分,我只想澄清关于我上面示例的第一部分:
PROPAGATION_REQUIRED
当传播设置为 PROPAGATION_REQUIRED 时,逻辑 为设置所在的每个方法创建事务范围 应用。每个这样的逻辑事务范围都可以确定 单独回滚状态,具有外部事务范围 在逻辑上独立于内部事务范围。的 当然,在标准 PROPAGATION_REQUIRED 行为的情况下,所有这些 范围将映射到相同的物理事务。所以一个 在内部事务范围内设置的仅回滚标记确实会影响 外部事务实际提交的机会(如您所料 它到)。
但是,在内部事务范围设置 rollback-only 标记,外部事务尚未决定 回滚本身,因此回滚(由内部无声触发 事务范围)是意外的。对应的 此时会引发 UnexpectedRollbackException。这是预期的 行为使交易的调用者永远不会被误导 假设实际上没有执行提交。所以如果一个 内部事务(外部调用者不知道)静默 将事务标记为仅回滚,外部调用者仍然调用 犯罪。外部调用者需要收到一个 UnexpectedRollbackException 清楚地表明回滚是 而是执行。
我的问题可以改写成这样:
逻辑事务范围是否包含事务属性?
【问题讨论】:
您可以参考***.com/questions/8490852/…了解多种场景的不同传播 【参考方案1】:所以,我设置了一个测试用例,简短的回答是肯定的。
事务逻辑范围保存事务属性,其边界确实是带注释的方法。
因此,即使两个方法的底层物理事务相同,逻辑属性也适用于每个方法,并且内部方法可以强制回滚外部方法事务。 但是,如果最后一次触发提交,则会导致 UnexpectedRollbackException。
参见。 Spring TransactionInterceptor(cmets 是我的)
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);
【讨论】:
注意:如果您使用调试器不信任内部变量状态,请显式调用 getter TransactionAspectSupport.currentTransactionStatus().isRollbackOnly() 想象一下你在 catch 之后应该做点别的事情,你的投掷方式很不方便【参考方案2】:根据我对规范的理解,我会在这个例子中说:
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”属性是否由内部逻辑事务范围管理处理?
顺便问一下,您使用的确切事务管理器类和版本是什么?
【讨论】:
【参考方案3】:请参阅spring documentation 的第 16.5.7 节。 即使内部方法在事务上下文中调用时使用 REQUIRED 注释,它也会映射到相同的物理事务。
【讨论】:
抱歉,您没有回答问题。以上是关于Spring @Transactional 注解属性优先级/继承的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring Boot 中使用 @Transactional 注解
Spring @Transactional 和 Spring @Lock 注解有啥关系?