有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring使用事务性重试

Spring重试是否保证与Spring的@Transactional注释一起工作

具体地说,我尝试使用@Retryable进行乐观锁定。这似乎取决于创建的AOP代理的顺序。例如,如果调用如下所示:

呼叫代码->;重试代理->;交易代理->;实际数据库代码

然后它将正常工作,但如果代理的结构如下所示:

呼叫代码->;交易代理->;重试代理->;实际数据库代码

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

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


共 (4) 个答案

  1. # 1 楼答案

    如果您正在使用Spring Boot,并且希望使用@Retryable,则需要执行以下操作:

    1. 将依赖项添加到pom:
    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
    </dependency>
    
    1. 在Spring引导应用程序中启用重试:
    @EnableRetry // <-- Add This
    @SpringBootApplication
    public class SomeApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SomeApplication.class, args);
        }
    
    }
    
    1. @Retryable注释您的方法:
    @Retryable(value = CannotAcquireLockException.class,
            backoff = @Backoff(delay = 100, maxDelay = 300))
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public boolean someMethod(String someArg, long otherArg) {
        ...
    }
    

    您可以使用@Retryable@Transactional对同一方法进行注释,它将按预期工作

  2. # 2 楼答案

    默认情况下,Spring Retry以相同的最低优先级生成通知-请查看RetryConfiguration。 但是,有一种非常简单的方法可以覆盖此顺序:

    @Configuration
    public class MyRetryConfiguration extends RetryConfiguration {
       @Override
       public int getOrder() {
          return Ordered.HIGHEST_PRECEDENCE;
       }
    }
    

    确保省略@EnableRetry注释以避免考虑默认RetryConfiguration

  3. # 3 楼答案

    如果您想独立地测试它并确定它的行为,那么您可以使用@Transactional@Service,然后是另一个使用transaction one并只添加重试次数的服务

    在这种情况下,无论您测试了多少,您都依赖于未记录的行为(注释处理的顺序如何)。根据创建独立Springbean的顺序等,这可能会在小版本之间发生变化。简言之,在同一方法上混合使用@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
    

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

  4. # 4 楼答案

    在这里找到了答案: https://docs.spring.io/spring/docs/5.0.6.BUILD-SNAPSHOT/spring-framework-reference/data-access.html#transaction-declarative-annotations 表2表明Transactional注释的通知的顺序为Ordered.LOWEST_PRECEDENCE,这意味着只要不重写这些注释的通知顺序,就可以安全地将RetryableTransactional组合起来。换句话说,您可以安全地使用此表单:

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