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 注解有啥关系?

Spring 事务注解@Transactional

Spring——事务注解@Transactional建议收藏

Spring之Transactional注解

spring @Transactional注解参数详解