2025-05-29
스프링 트랜잭션
스프링 트랜잭션
Spring에서 트랜잭션을 올바르게 이해하고 활용하는 방법을 다룹니다. 프록시 기반 동작 원리, 전파 속성, 격리 수준, 예외 처리 시나리오를 살펴봅니다.
1. @Transactional의 동작 원리 (Proxy 기반)
Spring은 @Transactional을 만나면 실제 빈 대신 프록시 객체를 생성하여 트랜잭션을 관리합니다.
호출 흐름:
- Client → Proxy Bean 호출
- Proxy가
TransactionManager.getTransaction()으로 트랜잭션 시작 - Target(비즈니스 로직) 실행
- 예외 발생 여부에 따라 Commit 또는 Rollback
- 트랜잭션 종료
@Service
public class OrderService {
@Transactional
public void placeOrder(OrderDto dto) {
// 1) 재고 확인
// 2) 결제 처리
// 3) 주문 저장 (INSERT)
}
}2. 트랜잭션 전파 (Propagation)
메서드 간 트랜잭션 경계를 어떻게 공유할지 결정합니다.
| 전파 속성 | 설명 |
|---|---|
| REQUIRED | 기존 트랜잭션에 참여하거나 새로 생성 (기본값) |
| REQUIRES_NEW | 항상 새 트랜잭션 생성; 기존 트랜잭션 일시 중단 |
| SUPPORTS | 기존 트랜잭션이 있으면 참여; 없으면 트랜잭션 없이 실행 |
| NOT_SUPPORTED | 기존 트랜잭션이 있으면 일시 중단; 트랜잭션 없이 실행 |
| MANDATORY | 기존 트랜잭션 필수 |
| NEVER | 기존 트랜잭션이 있으면 거부 |
| NESTED | 기존 트랜잭션 내에 중첩 트랜잭션 생성 (Savepoint) |
@Transactional
public void outer() {
inner(); // inner()가 REQUIRED이면 outer의 트랜잭션에 참여
}
@Transactional(propagation = REQUIRES_NEW)
public void inner() {
// 독립 트랜잭션; inner의 롤백이 outer에 영향 없음
}3. 격리 수준 (Isolation Level)
동시성 문제를 어떻게 관리할지 제어합니다.
| 수준 | 설명 | 문제 |
|---|---|---|
| READ_UNCOMMITTED | 커밋되지 않은 데이터 읽기 허용 | Dirty Read |
| READ_COMMITTED | 커밋된 데이터만 읽기 (DB 기본값) | Non-Repeatable Read |
| REPEATABLE_READ | 동일 쿼리가 동일한 결과 반환 | Phantom Read |
| SERIALIZABLE | 완전한 격리 (직렬화) | — |
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void updateInventory(Long productId, int qty) {
// 같은 트랜잭션 내 쿼리는 일관된 재고 수량을 반환
}핵심 개념:
- Dirty Read: 다른 트랜잭션의 커밋되지 않은 데이터 읽기
- Non-Repeatable Read: 같은 트랜잭션 내에서 재조회 시 값이 다름
- Phantom Read: 같은 조건으로 재조회 시 새로운 행이 나타남
4. 롤백되지 않는 예외
기본적으로 @Transactional은 런타임 예외/에러에서 롤백하지만, Checked 예외에서는 커밋합니다.
@Transactional
public void process() {
throw new IOException("Checked exception"); // 기본적으로 롤백되지 않음
}롤백 조건 변경:
@Transactional(rollbackFor = Exception.class)
public void processAll() throws IOException {
// IOException도 롤백 트리거
}롤백 제외:
@Transactional(noRollbackFor = CustomException.class)
public void noRollback() {
throw new CustomException();
// 예외가 발생해도 롤백되지 않음
}마무리
@Transactional은 프록시 기반으로 동작하며, 같은 클래스 내부 호출에서는 우회됨- 동시성 요구사항에 맞게 전파 속성과 격리 수준을 적절히 설정
- 기본 RuntimeException 동작을 넘어서
rollbackFor/noRollbackFor로 조정
관련 글
벡터 유사도 기반76% 일치
스프링 내부 구조 정리
스프링의 핵심 내부 구조를 실제 코드와 테스트를 통해 정리합니다. IoC 컨테이너, Bean 생명주기, AOP, 의존성 주입 방식을 다룹니다.
76% 일치JPA와 Hibernate
JPA와 Hibernate를 깊이 이해하기 위한 네 가지 주제를 다룹니다. 영속성 컨텍스트의 동작 원리, Fetch 전략, N+1 문제 해결, 쿼리 성능 튜닝을 살펴봅니다.
68% 일치비동기와 병렬 처리
모던 백엔드 애플리케이션에서 지연 시간을 줄이고 리소스 활용을 극대화하기 위한 비동기 및 병렬 처리 기법을 다룹니다. Spring @Async, CompletableFuture, Java Concurrency, WebFlux를 살펴봅니다.