Spring Retry with Transactional

感情迁移 提交于 2019-12-05 17:31:38

问题


Is Spring Retry guaranteed to work with Spring's @Transactional annotation?

Specifically, I'm trying to use @Retryable for optimistic locking. It seems like it would be dependent on the ordering of the AOP proxies that were created. For example, if the calls look like this:

Calling code -> Retry Proxy -> Transaction Proxy -> Actual DB Code

Then it would work correctly, but if the proxies were structured like this:

Calling code -> Transaction Proxy -> Retry Proxy -> Actual DB Code

Then the retry wouldn't work, because the act of closing the transaction is what throws the optmistic locking exception.

In testing, it appeared to generate the first case (retry, then transaction), but I couldn't tell if this was a guaranteed behavior or just lucky.


回答1:


Found the answer here: https://docs.spring.io/spring/docs/5.0.6.BUILD-SNAPSHOT/spring-framework-reference/data-access.html#transaction-declarative-annotations Table 2 indicates that the advice for the Transactional annotation has an order of Ordered.LOWEST_PRECEDENCE, which means that it is safe to combine Retryable with Transactional as long as you aren't overriding the order of the advice for either of those annotations. In other words, you can safely use this form:

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



回答2:


If you want to test it independenty and be sure how it behaves then you may have @Transactional @Service, then another service that uses transaction one and just adds retries.

In this case, no matter how much you test you are relying on undocumented behaviour (how exactly annotations processing is ordered). This may change between minor releases, based on order in which independent Spring beans are created, etc etc. In short, you are asking for problems when you mix @Transactional and @Retry on same method.

edit: There is similar answered question https://stackoverflow.com/a/45514794/1849837 with code

@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

In that case it seems to be fine, because no matter what order is (retry then transaction, or transaction or retry) observable behaviour will be the same.




回答3:


By default Spring Retry builds advice with the same LOWEST_PRECEDENCE order - take a look at the RetryConfiguration. However, there is a pretty simple way to override this order:

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

Make sure to omit the @EnableRetry annotation to avoid default RetryConfiguration be taken into account.



来源:https://stackoverflow.com/questions/49678581/spring-retry-with-transactional

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!