기술과 산업/언어 및 프레임워크
Spring Boot 시리즈 17편 – 트랜잭션 관리 고급 전략: 선언적, 프로그래밍 방식, 전파/고립 수준까지 완벽 정리
B컷개발자
2025. 4. 28. 16:49
728x90
Spring Boot에서 트랜잭션 관리를 고급 수준으로 다루는 방법을 정리했습니다. 선언적 트랜잭션, 프로그래밍 방식, 전파(Propagation), 고립(Isolation) 수준까지 실전 중심으로 설명합니다.
Spring Boot 시리즈 17편 – 트랜잭션 관리 고급 전략: 선언적, 프로그래밍 방식, 전파/고립 수준까지 완벽 정리
트랜잭션(Transaction)은 데이터 무결성과 일관성을 유지하는 핵심 메커니즘입니다.
Spring Boot에서는 @Transactional 하나로 간단히 사용할 수 있지만,
상황에 맞는 전파(Propagation) 설정, 고립 수준(Isolation) 선택, 복잡한 트랜잭션 흐름 제어를 제대로 이해하지 못하면
의도치 않은 데이터 오류나 성능 저하를 초래할 수 있습니다.
이번 글에서는 실제 서비스 수준에서 필요한 트랜잭션 고급 관리 전략을 체계적으로 정리합니다.
📌 1. 트랜잭션 관리 방식 두 가지
방식 설명 특징
선언적(Declarative) | @Transactional 애노테이션 사용 | 코드 깔끔, 대부분 케이스 대응 가능 |
프로그래밍 방식(Programmatic) | TransactionTemplate, PlatformTransactionManager 직접 사용 | 세밀한 흐름 제어 가능, 복잡도↑ |
✅ 2. 선언적 트랜잭션 (@Transactional)
기본 사용법
@Service
@Transactional
public class OrderService {
public void placeOrder(OrderRequest request) {
// 주문 생성, 재고 감소, 포인트 적립 등
}
}
- 클래스 레벨에 선언하면 모든 public 메서드에 트랜잭션 적용
- 메서드 레벨에 별도로 선언할 수도 있음
주요 속성
속성 기본값 설명
propagation | REQUIRED | 기존 트랜잭션 있으면 참여, 없으면 새로 생성 |
isolation | DEFAULT | DB 기본 설정 사용 |
rollbackFor | Exception.class | 어떤 예외가 발생했을 때 롤백할지 지정 |
timeout | -1 (무제한) | 트랜잭션 제한 시간 설정 |
readOnly | false | 읽기 전용 힌트 (최적화에 도움) |
🔄 3. 트랜잭션 전파(Propagation) 상세 정리
트랜잭션 전파는 "트랜잭션이 이미 있을 때 어떻게 동작할 것인가"를 제어합니다.
옵션 설명 사용 예시
REQUIRED | (기본) 있으면 참여, 없으면 새로 시작 | 대부분의 서비스 로직 |
REQUIRES_NEW | 항상 새 트랜잭션 시작 (기존은 일시 중단) | 이벤트 기록, 별도 보장 로직 |
NESTED | 기존 트랜잭션 내부에 Savepoint 생성 | 부분 롤백이 필요한 경우 |
SUPPORTS | 있으면 참여, 없으면 비트랜잭션 실행 | 선택적 트랜잭션 |
NOT_SUPPORTED | 트랜잭션 없이 실행 | 로그 기록 등 성능 민감 작업 |
NEVER | 트랜잭션 있으면 예외 발생 | 트랜잭션 금지 영역 |
예시: REQUIRES_NEW 사용
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logEvent(Event event) {
eventRepository.save(event);
}
- 메인 비즈니스 트랜잭션 실패 여부와 관계없이 이벤트 기록은 반드시 남겨야 할 때 사용
⚙️ 4. 트랜잭션 고립 수준(Isolation) 설정
트랜잭션 고립 수준은 **동시성 문제(Dirty Read, Phantom Read, Non-repeatable Read 등)**를 어떻게 다룰지를 결정합니다.
수준 설명 동시성 제어 수준
READ_UNCOMMITTED | 커밋 안 된 데이터 읽기 허용 | 매우 낮음 (Dirty Read 발생 가능) |
READ_COMMITTED | 커밋된 데이터만 읽기 | 기본값 (SQL Server, Oracle) |
REPEATABLE_READ | 조회한 데이터는 트랜잭션 동안 일관 | MySQL InnoDB 기본 |
SERIALIZABLE | 모든 트랜잭션 직렬화 처리 | 최고 수준, 성능 저하 큼 |
예시: SERIALIZABLE 적용
@Transactional(isolation = Isolation.SERIALIZABLE)
public void criticalStockCheck() {
// 재고 수량을 엄격하게 일관성 있게 조회
}
- 동시 재고 감소, 결제 처리 등 강한 일관성이 필요한 작업에 사용
🔥 5. 프로그래밍 방식 트랜잭션 관리
더 세밀한 흐름 제어가 필요할 경우 TransactionTemplate을 사용할 수 있습니다.
@Service
public class ManualTransactionService {
private final TransactionTemplate transactionTemplate;
public ManualTransactionService(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public void executeManualTransaction() {
transactionTemplate.executeWithoutResult(status -> {
// 여기서 로직 실행
});
}
}
- 복잡한 분기/조건부 커밋/조건부 롤백이 필요한 경우 활용
- 선언적 방식보다 복잡도는 높지만 제어력은 더 강력
🧠 실무 트랜잭션 설계 팁
항목 전략
서비스 레이어 중심 | 트랜잭션은 반드시 서비스(Service) 계층에만 선언 |
내부 호출 주의 | 같은 클래스 내 메서드 호출은 프록시 적용되지 않음 (self-injection 필요) |
분리된 책임 관리 | 트랜잭션 경계를 로직 단위가 아닌 비즈니스 단위로 설정 |
커스텀 롤백 | rollbackFor = CustomException.class로 특정 예외 롤백 지정 |
DB 락 주의 | SERIALIZABLE 사용 시 DB 락 장기 점유 주의 필요 |
✅ 마무리 요약
항목 요약
기본 사용 | @Transactional로 간단하게 선언 |
고급 설정 | Propagation, Isolation, Rollback 조건 세밀 제어 |
프로그래밍 방식 | TransactionTemplate으로 복잡 흐름 대응 가능 |
실무 설계 | 서비스 레이어 중심, 동시성/일관성 균형 맞추기 |
테스트 전략 | DB 롤백 테스트 (@Transactional + @Rollback) 적극 활용 |
📌 다음 편 예고
Spring Boot 시리즈 18편: 멀티 모듈 프로젝트의 테스트 전략 – 독립성, 속도, 신뢰성 확보 방법
728x90