使用事务性进行春季重试

2022-09-01 14:40:04

Spring Retry 是否保证与 Spring 的注释配合使用?@Transactional

具体来说,我试图用于乐观锁定。它似乎取决于创建的AOP代理的顺序。例如,如果调用如下所示:@Retryable

调用代码 -> 重试代理 ->事务代理 ->实际数据库代码

然后它可以正常工作,但如果代理的结构是这样的:

调用代码 -> 事务代理 -> 重试代理 ->实际数据库代码

然后重试将不起作用,因为关闭事务的行为会引发选择性锁定异常。

在测试中,它似乎生成了第一个情况(重试,然后是事务),但我无法判断这是有保证的行为还是只是幸运的。


答案 1

在这里找到了答案:https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html#tx-decl-explained 表 2 表明注释的建议顺序为 ,这意味着只要您不覆盖这些注释中任何一个的建议的顺序,就可以安全地与之结合使用。换句话说,您可以安全地使用此表单:TransactionalOrdered.LOWEST_PRECEDENCERetryableTransactional

@Retryable(StaleStateException.class)
@Transactional
public void performDatabaseActions() {
    //Database updates here that may cause an optimistic locking failure 
    //when the transaction closes
}

答案 2

如果你想独立地测试它,并确保它的行为方式,那么你可能有@Transactional @Service,然后是另一个使用事务一的服务,只是添加重试。

在这种情况下,无论你测试多少,你都依赖于未记录的行为(注释处理的确切顺序)。这可能会在次要版本之间发生变化,具体取决于创建独立Spring bean的顺序等。简而言之,当您将@Transactional混合并@Retry相同的方法时,您正在询问问题。

编辑:有类似的问题 https://stackoverflow.com/a/45514794/1849837 与代码

@Retryable(StaleStateException.class)
@Transactional
public void doSomethingWithFoo(Long fooId){
    // read your entity again before changes!
    Foo foo = fooRepository.findOne(fooId);
    foo.setStatus(REJECTED)  // <- sample foo modification
} // commit on method end

在这种情况下,它似乎很好,因为无论顺序是什么(重试然后事务,或事务或重试)可观察的行为都是相同的。


推荐