Spring Retryは、Springの@Transactional
アノテーションで動作することが保証されていますか?
具体的には、楽観的ロックに@Retryable
を使用しようとしています。作成されたAOPプロキシの順序に依存しているようです。たとえば、呼び出しが次のようになっているとします。
呼び出しコード->再試行プロキシ->トランザクションプロキシ->実際のDBコード
その後、正しく機能しますが、プロキシが次のように構成されている場合:
呼び出しコード->トランザクションプロキシ->再試行プロキシ->実際のDBコード
その後、トランザクションを閉じる動作がオプティミスティックロック例外をスローするため、再試行は機能しません。
テストでは、最初のケース(再試行、次にトランザクション)を生成するように見えましたが、これが保証された動作なのか、それともラッキーなのかはわかりませんでした。
ここで答えを見つけました: 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
であることを示しています。つまり、Retryable
をTransactional
と組み合わせても安全です。これらの注釈のどちらについても、アドバイスの順序を上書きすることはありません。つまり、このフォームを安全に使用できます。
@Retryable(StaleStateException.class)
@Transactional
public void performDatabaseActions() {
//Database updates here that may cause an optimistic locking failure
//when the transaction closes
}
デフォルトでは、Spring Retryは同じLOWEST_PRECEDENCE順序でアドバイスを作成します-RetryConfigurationを見てください。ただし、この順序をオーバーライドする非常に簡単な方法があります。
@Configuration
public class MyRetryConfiguration extends RetryConfiguration {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
デフォルトのRetryConfigurationが考慮されないように、必ず@EnableRetryアノテーションを省略してください。
独立してテストし、その動作を確認する場合は、@ Transactional @Serviceを使用し、次にトランザクション1を使用して再試行を追加する別のサービスを使用できます。
この場合、どれだけテストしても、文書化されていない動作(注釈処理の順序の正確さ)に依存しています。これは、マイナーリリース間で、独立した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
その場合、監視可能な動作は同じであるため(再試行後にトランザクション、またはトランザクションまたは再試行)の順序に関係なく、問題はないようです。