2017-12-10 15 views
8

에 롤백 트랜잭션이 엔티티가봄 데이터 : 낙관적 인 방식으로 구현</p> <pre><code>@Entity class A { ... @Version int version; } </code></pre> <p><code>A</code> 인스턴스 업데이트 : 재시도

의견에 명시된 바와 같이
@Transactional(rollbackFor = {StaleStateException.class}) 
@Retryable(value = {StaleStateException.class}) 
public void updateA() { 
    A a = findA(); 
    B b = new B(); 
    // Update "a" somehow 
    a.update(); 
    // "b" is saved on each retry! 
    save(b); 
} 

는, 그 트랜잭션이 롤백 할되지 않은 것 같다 때 StaleStateException 각 재시도시 B 인스턴스가 저장됩니다.

재시도시 트랜잭션을 롤백 할 수 있습니까?

희망하는 동작은 성공한 a 업데이트에서만 b이 저장된다는 것입니다.

답변

7

나는 @Retryable 구성과 관련이있을 것이라고 생각합니다.

의사가 https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statelessRetry라고 말했듯이 상태 비 저장 재시도는 성공할 때까지 동일한 방법을 계속 호출하는 순환입니다.

문제는 매번 실패 할 때마다 호출 된 첫 번째 인터셉터가 예외를 다시 발생시키지 않으므로 재시도가 발생하지 않으므로 @Transactional에 도달하지 않는다는 것입니다.

그래서 모든 재 시도가 컨텍스트에서 new B()과 동일한 열린 트랜잭션을 다시 사용하는 기본 트랜잭션 전파를 따릅니다.

내가 올바른 방향으로 디버깅을하고 있는지 확인할 수 있습니다. 두 번째 재시도를 입력하면 A이 업데이트 블록 전에 이미 업데이트 된 것을 확인한 후 올바르게해야합니다.

당신은 2 가지 방법으로 해결할 수 있습니다 :

하나는 트랜잭션이 처음으로 롤백 그래서 두 개의 블록 (중첩 된 트랜잭션과 첫 시도)

@Retryable(value = {StaleStateException.class}) 
public void retryableUpdate() { 
    updateA(); 
} 

@Transactional(rollbackFor = {StaleStateException.class}) 
public void updateA() { 
    A a = findA(); 
    B b = new B(); 
    // Update "a" somehow 
    a.update(); 
    // "b" is saved on each retry! 
    save(b); 
} 

를 나눕니다.

또는 문서를 읽고 상태 저장 재시도를 사용할 수 있습니다. https://docs.spring.io/spring-batch/trunk/reference/html/retry.html#statefulRetry