이전 - [Java] JPA 낙관적 락(Optimistic) 동시성 제어 - 1
위 낙관적 락을 이용하여 버전 충돌 시 OptimisticLockingFailureException 오류가 발생하는 것을 알 수 있었다.
그렇다면 동시성 제어를 완벽히 하기 위해 위 오류를 어떻게 해결해야 할까?
try-catch 로 예외처리를 잡아 무한루프를 돌려도 되겠지만, 좀 더 간결하고 좋은 방법을 고민하다 Spring에서 지원하는 Retry 라이브러리를 채택하였다.
Spring Retry는 실패한 작업을 재호출하는 기능을 제공한다.
//Spring Retry
implementation 'org.springframework.retry:spring-retry'
@Configuration
@EnableRetry
public class CommonConfig {...}
따라서 서비스 코드에 아래와 같이 @Retryable 을 추가
@Service
@RequiredArgsConstructor
public class SeqService {
private final SeqRepository seqRepository;
@Retryable(maxAttempts = 10, value = {ObjectOptimisticLockingFailureException.class, DataIntegrityViolationException.class}, backoff = @Backoff(delay = 500))
public String getSeq(Seq.Type type) {
Long num = this.generationNum(type);
return String.format("%s-%s", type.name(), StringUtils.leftPad(num.toString(), 6, "0"));
}
@Transactional
Long generationNum(Seq.Type type) {
Seq seq = seqRepository.findBySeqType(type).orElse(Seq.builder()
.seqType(type)
.num(0L)
.build());
seq.numUp();
return seqRepository.save(seq)
.getNum();
}
}
위 코드와 같이 Retryable만 붙여주면 아래와 같이 동시성 제어가 통과됨을 볼 수 있다.
DataIntegrityViolationException 를 추가로 재시도하는 이유는 서비스 내에서 orElse를 보면 INSERT도 같이 존재하기에 중복 충돌까지 같이 방지하기 위하여 추가하였다.

