Spring Transaction Strategy
Overview
Spring의 @Transactional
어노테이션은 매우 유용하지만, 기본 동작 방식에 대한 오해는 종종 데이터 정합성 문제로 이어질 수 있음. 해당 포스트에서는 핵심적인 두 가지 질문에 대해 명확히 짚으려 함
롤백(Rollback)의 기본 규칙: Unchecked Exception
vs Checked Exception
가장 흔한 오해는 “예외가 발생하면(모든) 롤백을 일으킨다.” 이는 오해
예외 종류 | 기본 동작 | 예시 | Spring의 의도 |
---|---|---|---|
Unchecked Exception |
⭕️ 롤백 (Rollback) | RuntimeException 및 그 하위 클래스들 (NullPointerException , IllegalArgumentException , FeignException 등) |
“복구 불가능한 시스템 오류/버그”. 데이터 정합성이 깨졌을 가능성이 높으므로 즉시 롤백하여 작업을 되돌린다. |
Checked Exception |
❌ 커밋 (Commit) | IOException , SQLException , JsonProcessingException 등 Exception 을 상속하지만 RuntimeException 이 아닌 클래스들 |
“복구 가능한 예외”. 개발자가 try-catch 로 처리하여 비즈니스 로직을 이어갈 수 있다고 간주한다. 따라서 예외가 처리될 것을 기대하고 트랜잭션을 커밋한다. |
결론: 질문하신 내용과 달리, Spring은 기본적으로
Checked Exception
에 대해서는 롤백을 수행하지 않습니다.
롤백 정책 제어하기: @Transactional
속성
Spring은 개발자가 이 기본 동작을 제어할 수 있도록 강력한 옵션을 제공함
rollbackFor
: 특정Checked Exception
이 발생했을 때도 롤백을 강제하고 싶을 때 사용함// JsonProcessingException (Checked Exception)이 발생해도 롤백하도록 설정 @Transactional(rollbackFor = JsonProcessingException.class) public void processJson() throws JsonProcessingException { // ... }
noRollbackFor
: 특정Unchecked Exception
이 발생했을 때 예외적으로 롤백을 막을 수 도 있음// MyBusinessAlertException (RuntimeException)이 발생해도 롤백하지 않도록 설정 @Transactional(noRollbackFor = MyBusinessAlertException.class) public void processWithAlert() { // ... }
아키텍처 시나리오별 트랜잭션 전략
시나리오 A: 단일 데이터베이스 트랜잭션
가장 일반적인 경우로, 하나의 비즈니스 유스케이스가 단일 데이터베이스 내의 여러 테이블을 변경하는 상황
- 전략: 유스케이스가 시작되는 가장 바깥쪽의 애플리케이션 서비스 메소드에
@Transactional
을 선언함 - 예시:
TicketEventHandleSampleService.issue()
- 동작: 이 메소드에서 시작된 트랜잭션은 내부적으로 호출되는 모든 Repository 메소드에 전파(propagation)되어, 모든 DB 작업이 하나의 원자적인 단위로 묶이며, 중간에
RuntimeException
이 발생하면 모든 작업이 롤백됨
–>