[Spring] @Transactional 롤백은 언제 되는 걸까?

Hocaron·2022년 6월 20일
0

Spring

목록 보기
23/44
post-custom-banner

에러(Error)와 예외(Exception)

프로그래밍에서 예외란 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 경우를 말한다. 그리고 자바에서 예외는 개발자가 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링할 수 있다.

그러나, 에러는 시스템에 무엇인가 비정상적인 상황이 발생한 경우를 말한다. 주로 자바 가상 머신에서 발생하는 것이며, 예외와 반대로 이를 애플리케이션 코드에서 잡을 수 없다. 에러의 예시로는 OutOfMemoryError, ThreadDeath, StackOverflowError 등이 있다.

예외 구분

예외는 아래 그림과 같이 Checked Exception과 Unchecked Exception으로 구분할 수 있다. 쉽게 말하면, RuntimeException을 상속하지 않은 클래스는 Checked Exception, 반대로 상속한 클래스는 Unchecked Exception으로 분류할 수 있다.

Unchecked Exception
명시적인 예외 처리를 강제하지 않기 때문에 Uncheked Exception이라고 한다. 명시적인 예외 처리란 try ~ catch로 예외를 잡거나 throw로 호출한 메소드에게 예외를 던지지 않는 행위를 말한다.

Checked Exception
명시적인 예외 처리를 강제하기 때문에 Checked Exception이라 한다. 반드시 try ~ catch로 예외를 잡거나 throw로 호출한 메소드에게 예외를 던져야 한다.

정리하면

Checked Exception이 Rollback되지 않는 이유
기본적으로 Checked Exception은 복구가 가능하다는 메커니즘을 가지고 있다. 예를 들어, 특정 이미지 파일을 찾아서 전송해 주는 함수에서 이미지를 찾지 못 했을 경우 기본 이미지를 전송한다는 복구 전략을 가질 수 있다. 정리하자면, 복구가 가능하니 Rollback은 진행하지 않는다는 의미이다.

예외 처리 방법

예외 복구

예외 상황을 파악하고 문제를 해결하여 정상 상태로 돌려 놓는 방법이다.

예외 처리 회피

예외 처리를 직접 담당하지 않고 호출한 쪽으로 던져 회피하는 방법이다. 긴밀하게 역할을 분담하고 있는 관계가 아닐 경우 예외를 던지는 것은 무책임한 방법이다.

public Object someMethod() throws IOException {
        ...
}

예외 전환

예외 처리 회피와 비슷하게 메소드 밖으로 예외를 던지지만, 그냥 던지지 않고 적절한 예외로 전환해서 넘기는 방법이다. 명확한 의미로 전달되기 위해 적합한 의미를 가진 예외로 변경해야 한다.

public Object method() {
        try {
                ...
        } catch (IOException e) {
                throw new CustomException ("IOException 발생");
        }
}

public class CustomException extends RuntimeException{
    public CustomException(String message) {
        super(message);
    }
}

정리하면

  • 예외 복구 전략이 명확하고 복구가 가능하면 Checked Exception을 try-catch로 잡아서 예외 복구를 하거나, 코드의 흐름으로 제어하는 것이 좋다.
  • 그러나 이러한 경우는 흔하지 않기 때문에 Checked Exception이 발생하면 더 구체적인 UnChecked Exception을 발생시키고 예외에 대한 메시지를 명확하게 전달하는 것이 효과적이다.
  • 무책임하게 상위 메서드에 throw로 예외를 던지는 행위를 하지 않는 것이 좋다. 상위 메서드들의 책임이 그만큼 증가하기 때문이다.
  • Checked Exception은 기본 트랜잭션 속성에서 Rollback을 진행하지 않는다.

@Transactional 롤백은 언제 되는 걸까?

스프링은 디폴트로 UnCheckedException 과 Error에 대해서 롤백 정책을 설정한다.


둘은 같다.

만약 디폴트 값으로 @Transactional을 설정했다면, 아래와 같은 상황에서는?


이런 경우는 롤백이 기본적으로 되지 않는다. 결국 데이터베이스에는 값이 들어가게 된다.

rollbackFor은 그럼 언제쓸까?

먼저 스프링이 RuntimeException을 관리하는 것을 잊지 않는 게 중요하다. 만약에 Checked Exception 이 발생했을 때 트랜잭션이 롤백이 되지 않고 디비에 변경이 되는 것을 모르고 있을 때가 문제가 된다. 모든 예외에 대해서 전부 트랜잭션을 롤백하고 싶다면
@Transactional(rollbackFor = {Exception.class}
으로 설정을 해야 롤백이 된다.
결론은 롤백이 언제 되는지 정확히 파악하고 애플리케이션에 맞게 설정을 하자.

References

profile
기록을 통한 성장을
post-custom-banner

0개의 댓글