기술과 산업/언어 및 프레임워크
Spring Boot 고급 시리즈 3화 – 트랜잭션 전파와 고립 수준, 언제 어떻게 사용할까?
B컷개발자
2025. 6. 5. 18:24
728x90
트랜잭션 처리는 단순히 @Transactional 어노테이션을 붙이는 것으로 끝나지 않습니다. 실제 서비스 로직이 복잡해질수록 트랜잭션의 “전파(propagation)”와 “고립 수준(isolation level)”을 이해하고 적절히 사용하는 것이 중요해집니다. 이 글에서는 두 개념을 하나씩 짚어보며, 실전에서 어떤 상황에 어떤 전략을 택하는 것이 좋을지 깊이 있게 살펴보겠습니다.
트랜잭션 전파(Propagation) – 어떤 트랜잭션을 따를 것인가?
스프링은 메서드 실행 시, 현재 트랜잭션이 존재하는지 여부에 따라 새로운 트랜잭션을 생성하거나 기존 트랜잭션을 이어받는 전략을 Propagation 속성으로 제어할 수 있게 합니다.
자주 쓰는 전파 전략
전파 옵션설명실전 사용 예
REQUIRED | 기본값. 기존 트랜잭션 있으면 참여, 없으면 새로 생성 | 대부분의 서비스 메서드 |
REQUIRES_NEW | 항상 새 트랜잭션 생성 (기존 트랜잭션은 잠시 중단됨) | 메일 전송 로그, 감사 기록 등 메인 트랜잭션과 분리해야 할 때 |
NESTED | 내부 트랜잭션처럼 동작. 롤백 범위 제어에 유리 | 배치 처리를 부분 롤백해야 할 때 |
NOT_SUPPORTED | 트랜잭션 없이 실행 | 캐시 초기화나 단순 로그 출력 등 비트랜잭션 작업 |
NEVER | 트랜잭션 있으면 예외 발생 | 트랜잭션 내 호출이 금지된 환경에서 방어용 |
⚠️ 주의: REQUIRES_NEW는 물리적으로 새로운 트랜잭션을 열기 때문에 DB 연결 리소스를 더 소비합니다. 무분별한 사용은 커넥션 풀 고갈로 이어질 수 있습니다.
트랜잭션 고립 수준(Isolation Level) – 읽기 일관성 보장의 단계
고립 수준은 트랜잭션 간의 데이터 간섭을 어떻게 방지할 것인지를 결정하는 전략입니다. SQL 표준에서 정의한 고립 수준은 4가지이며, 스프링에서는 JDBC를 통해 이를 제어합니다.
고립 수준허용되는 현상주요 특징
READ_UNCOMMITTED | Dirty Read 허용 | 거의 사용 안 함 |
READ_COMMITTED | Dirty Read 차단 | 대부분의 DBMS 기본값 |
REPEATABLE_READ | Non-repeatable Read 방지 | 동일 쿼리 결과가 일관되게 유지됨 |
SERIALIZABLE | 모든 현상 방지 | 가장 엄격, 성능 저하 있음 |
실전 팁
- 읽기만 하는 서비스에는 READ_COMMITTED가 적절합니다.
- 재고 수량 변경처럼 정확한 수치가 중요한 경우에는 REPEATABLE_READ 이상을 고려해야 합니다.
- 거래 중복 방지를 위해 SERIALIZABLE을 쓰는 것은 가능하지만, 락 경합이 심하므로 필요 시에만 신중하게 사용해야 합니다.
트랜잭션 속성 설정 예시
@Transactional(
propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.REPEATABLE_READ,
timeout = 5,
rollbackFor = CustomException.class
)
public void recordAuditLog(AuditData data) {
// 감사 로그는 메인 트랜잭션과 분리해서 별도로 기록
}
이 설정은 다음과 같은 의미입니다:
- 새로운 트랜잭션을 열고
- 일관된 읽기 보장을 위해 REPEATABLE_READ 고립 수준을 설정하며
- 5초 안에 완료되지 않으면 롤백
- CustomException이 발생했을 경우에만 롤백합니다.
언제 무엇을 써야 할까 – 실무 전략
- 서비스 계층 전반: REQUIRED 기본 전략 유지
- 중요 로그, 알림, 외부 시스템 연동: REQUIRES_NEW로 독립 트랜잭션 분리
- 부분 롤백이 필요한 작업: NESTED를 고려
- 단순 조회 서비스: readOnly = true 설정 + READ_COMMITTED
트랜잭션은 전략이다
스프링 트랜잭션은 막연히 붙이는 것이 아닙니다. 전파와 고립 수준을 이해하고, 그것을 코드의 전략으로 삼는 것이 진짜 실무자의 역량입니다. 트랜잭션 설정은 때로는 성능과 직결되고, 때로는 데이터 일관성의 최후 보루가 됩니다.
복잡한 시스템일수록 작은 설정 하나가 전체 서비스의 품질을 좌우합니다. 이번 글을 통해 단순히 개념을 넘어서, 실전에서 의사결정을 내릴 수 있는 기준이 생기기를 바랍니다.
728x90