简体   繁体   English

Spring @Transactional Annotation属性优先级/继承

[英]Spring @Transactional Annotation properties precedence / inheritance

In the case of REQUIRED propagation when the caller method itself is transactionnal does the current method overrides enclosing transaction properties (for example rollbackFor) if they are different ? 在调用方法本身是transactionnal的情况下,当REQUIRED传播的情况下,如果它们不同,当前方法是否会覆盖封闭的事务属性(例如rollbackFor)?

illustration : 插图:

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() {
        [...]
    }
}

edit : 编辑

Well, i'd like to avoid trivial out of scope answers, so let's be clear, I'am aware of spring propagation handling. 好吧,我想避免琐碎的范围答案,所以我们要清楚,我知道弹簧传播处理。

If you're not, below is the relevant part of the documentation, I just would like to clarify the first part regarding my example above : 如果你不是,下面是文档的相关部分,我只想澄清关于我上面例子的第一部分:

PROPAGATION_REQUIRED PROPAGATION_REQUIRED

When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope is created for each method upon which the setting is applied. 当传播设置为PROPAGATION_REQUIRED时,将为应用该设置的每个方法创建逻辑事务范围。 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. 当然,在标准PROPAGATION_REQUIRED行为的情况下,所有这些范围将映射到同一物理事务。 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). 因此,内部事务范围中的仅回滚标记集确实会影响外部事务实际提交的机会(正如您所期望的那样)。

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. 此时抛出相应的UnexpectedRollbackException。 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. 因此,如果内部事务(外部调用者不知道)以静默方式将事务标记为仅回滚,则外部调用者仍会调用commit。 The outer caller needs to receive an UnexpectedRollbackException to indicate clearly that a rollback was performed instead. 外部调用者需要接收UnexpectedRollbackException以清楚地指示已执行回滚。

My question can be reworded as this : 我的问题可以改写为:

Does the logical transaction scope holds the transaction properties ? 逻辑事务范围是否包含事务属性?

So, I set up a test case, the short answer is yes. 所以,我设置了一个测试用例,简短的回答是肯定的。

The transaction logical scope holds the transaction properties and its boundaries are indeed the annotated method ones. 事务逻辑范围包含事务属性,其边界确实是带注释的方法属性。

So even if the underlying physical transaction is the same for both methods, the logical properties are proper to each method and the inner method can so force the rollback of the outer method transaction. 因此,即使两个方法的底层物理事务都相同,逻辑属性也适用于每个方法,而内部方法可以强制回滚外部方法事务。 If this last trigger a commit however it will lead to a UnexpectedRollbackException. 如果最后一次触发提交,则会导致UnexpectedRollbackException。

cf. 比照 Spring TransactionInterceptor (comments are mine) Spring TransactionInterceptor(评论是我的)

try {
        retVal = invocation.proceed();
}
catch (Throwable ex) {
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
}

completeTransactionAfterThrowing() : completeTransactionAfterThrowing():

// txinfo is proper to the invocation target method
if (txInfo.transactionAttribute.rollbackOn(ex)) {
            try {
                txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
            }

AbstractPlatformTransactionManager.processRollback() : AbstractPlatformTransactionManager.processRollback():

else if (status.isNewTransaction()) { //requiresnew
    doRollback(status);
}
else if (status.hasTransaction()) { //requiered
        [...]
        doSetRollbackOnly(status);
    }
}

In my understanding of the specifications, I would say in this example : 在我对规范的理解中,我会在这个例子中说:

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() {
        [...]
    }
}

So we can reformulate the question as : does overridden "rollbackFor" property is handled by inner logical transaction scope management ? 因此我们可以将问题重新表述为: 重写的“rollbackFor”属性是否由内部逻辑事务范围管理处理?

By the way, what is the exact transaction manager class and version you use ? 那么,您使用的确切事务管理器类和版本是什么?

Refer Section 16.5.7 of spring documentation . 请参阅弹簧文档的第16.5.7节。 Even though inner methods are annotate with REQUIRED when it is called within in transaction context, it will mapped to same physical transaction. 即使在事务上下文中调用内部方法时,内部方法也使用REQUIRED进行注释,但它将映射到同一物理事务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM