개발/devOps(운영 이슈 처리)

Spring @Transactional에서 왜 RuntimeException만 롤백될까?

jineddy 2025. 6. 19. 16:41
728x90

@Transactional은 Spring에서 가장 많이 사용되는 어노테이션 중 하나입니다. 데이터베이스 트랜잭션 관리를 간단하게 처리해주지만, 의외로 많은 분들이 궁금해하는 부분이 있습니다.

" 왜 RuntimeException만 기본적으로 트랜잭션이 롤백되고, Checked Exception은 롤백되지 않을까요?"

이번 글에서는 Spring의 트랜잭션 롤백 정책예외 처리 방식, 그리고 롤백 대상을 지정하는 방법까지 자세히 알아보겠습니다.

 

Spring @Transactional 기본 롤백 정책

Spring에서는 @Transactional 어노테이션이 붙은 메서드에서 예외가 발생했을 때, 기본적으로 아래 조건에 따라 트랜잭션을 롤백합니다:

예외 유형 트랜잭션 롤백 여부 예시
RuntimeException 및 그 하위 클래스 롤백됨 NullPointerException, IllegalArgumentException
Error 롤백됨 OutOfMemoryError, StackOverflowError
Checked Exception 롤백 안 됨 IOException, SQLException

즉, 개발자가 throws를 선언해야 하는 Checked Exception은 기본 설정에서 롤백되지 않습니다.

 

RuntimeException만 롤백될까?

1. Java의 예외 철학

Java에서는 예외를 두 가지로 나눕니다:

  • Checked Exception: 복구 가능한 예외 (IOException, SQLException 등)
  • Unchecked Exception: 복구 불가능한 예외 (NullPointerException, IllegalStateException 등)

Spring은 복구 가능한 예외(Checked)는 직접 처리하라, 복구 불가능한 예외(Runtime)는 자동으로 롤백해준다는 철학을 따릅니다.

2. 트랜잭션의 안정성 확보

RuntimeException은 예측이 어려운 오류를 나타내기 때문에, Spring은 이를 감지하면 자동으로 트랜잭션을 롤백하여 데이터의 무결성을 지키려 합니다.

 

Checked Exception도 롤백하려면?

Spring에서는 @Transactional 어노테이션에 rollbackFor 속성을 지정하면 됩니다.

@Transactional(rollbackFor = IOException.class)
public void saveData() throws IOException {
    throw new IOException("Checked Exception 발생");
}

 

여러 개의 예외를 지정할 수도 있습니다:

@Transactional(rollbackFor = {IOException.class, SQLException.class})

 

실무 팁: 예외 설계 전략

 

  • 복구 가능한 오류는 Checked Exception으로 선언하고 try-catch 처리하는 것이 좋습니다.
  • 롤백이 필요한 예외는 RuntimeException을 상속한 **커스텀 예외(Custom Exception)**로 설계하는 것이 안전합니다.
public class CustomBusinessException extends RuntimeException {
    public CustomBusinessException(String message) {
        super(message);
    }
}

 

 

결론

 

  • @Transactional은 기본적으로 RuntimeExceptionError에만 반응하여 트랜잭션을 롤백합니다.
  • 이는 Java 예외 처리 철학에 따른 Spring의 기본 설계입니다.
  • Checked Exception도 롤백 대상에 포함시키고 싶다면, rollbackFor 속성을 꼭 활용하세요.

 

728x90