Spring/Spring JPA
[JPA] @Transactional의 propagation 속성 자세히
개발자잡
2024. 12. 26. 15:34
@Transactional의 propagation 속성은 트랜잭션의 전파(Propagation) 동작을 정의합니다. 전파는 메서드가 실행될 때 기존 트랜잭션에 참여할지, 새로운 트랜잭션을 시작할지, 혹은 트랜잭션 없이 실행할지를 결정합니다.
Propagation의 주요 개념
Propagation은 트랜잭션 관리 중 다른 트랜잭션 환경과의 상호작용 방식을 정의하는 데 사용됩니다. 이는 주로 A 메서드가 트랜잭션 B 메서드를 호출할 때 트랜잭션 상태를 어떻게 처리할지를 결정합니다.
Propagation의 종류
스프링에서는 아래와 같은 전파 유형을 제공합니다:
Propagation Type | 설명 | 예제 상황 |
REQUIRED | 기본값. 기존 트랜잭션이 있으면 참여하고, 없으면 새 트랜잭션을 시작합니다. | 서비스 계층에서 트랜잭션이 없으면 새 트랜잭션 시작. 이미 트랜잭션이 있으면 해당 트랜잭션에 참여. |
REQUIRES_NEW | 항상 새로운 트랜잭션을 생성하고, 기존 트랜잭션을 일시 중단합니다. | 독립적인 트랜잭션이 필요할 때, 예를 들어 로그를 저장하는 작업. |
SUPPORTS | 트랜잭션이 있으면 참여하고, 없으면 트랜잭션 없이 실행됩니다. | 메서드가 반드시 트랜잭션에 의존하지 않는 경우. |
NOT_SUPPORTED | 항상 트랜잭션 없이 실행하며, 기존 트랜잭션이 있으면 일시 중단됩니다. | 배치 작업 등 트랜잭션이 필요 없는 작업. |
MANDATORY | 반드시 기존 트랜잭션이 있어야 하며, 없으면 예외를 발생시킵니다. | 트랜잭션 없이 실행되면 안 되는 핵심 작업. |
NEVER | 트랜잭션 없이 실행되며, 트랜잭션이 이미 있으면 예외를 발생시킵니다. | 트랜잭션에서 실행되면 안 되는 작업. |
NESTED | 기존 트랜잭션이 있으면 중첩 트랜잭션을 생성하고, 없으면 새로운 트랜잭션을 시작합니다. (Savepoint 사용) | 트랜잭션 내부에서 독립적으로 롤백할 필요가 있는 경우. |
Propagation 종류별 동작 방식
1. REQUIRED (기본값)
- 기존 트랜잭션이 존재하면 참여합니다.
- 기존 트랜잭션이 없으면 새 트랜잭션을 생성합니다.
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// A 메서드에서 새로운 트랜잭션 시작
methodB(); // 이미 존재하는 트랜잭션에 참여
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
// 트랜잭션이 생성되지 않음 (A의 트랜잭션에 참여)
}
2. REQUIRES_NEW
- 항상 새로운 트랜잭션을 생성합니다.
- 기존 트랜잭션은 일시 중단됩니다.
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB(); // 새로운 트랜잭션 시작
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// methodB의 트랜잭션은 methodA와 독립적으로 동작
}
- 사용 예: 로그 저장이나 비즈니스 로직이 독립적으로 처리되어야 하는 경우.
3. SUPPORTS
- 트랜잭션이 존재하면 참여합니다.
- 트랜잭션이 없으면 트랜잭션 없이 실행됩니다.
@Transactional(propagation = Propagation.SUPPORTS)
public void method() {
// 트랜잭션이 존재하면 참여, 없으면 트랜잭션 없이 실행
}
- 사용 예: 읽기 전용 작업 또는 트랜잭션이 필수적이지 않은 작업.
4. NOT_SUPPORTED
- 트랜잭션이 있으면 일시 중단하고, 항상 트랜잭션 없이 실행됩니다.
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void method() {
// 항상 트랜잭션 없이 실행
}
- 사용 예: 성능이 중요한 비트랜잭션 작업
5. MANDATORY
- 반드시 기존 트랜잭션이 존재해야 합니다.
- 트랜잭션이 없으면 예외를 던집니다.
@Transactional(propagation = Propagation.MANDATORY)
public void method() {
// 트랜잭션이 없으면 IllegalTransactionStateException 발생
}
- 사용 예: 트랜잭션 없이 실행되면 안 되는 중요한 작업.
6. NEVER
- 트랜잭션 없이 실행됩니다.
- 트랜잭션이 존재하면 예외를 던집니다.
@Transactional(propagation = Propagation.NEVER)
public void method() {
// 트랜잭션이 존재하면 예외 발생
}
- 사용 예: 트랜잭션 환경에서 실행되면 안 되는 작업.
7. NESTED
- 기존 트랜잭션이 있으면 중첩 트랜잭션을 생성합니다.
- 기존 트랜잭션이 없으면 새로운 트랜잭션을 생성합니다.
- 중첩 트랜잭션은 부모 트랜잭션과 독립적으로 롤백할 수 있습니다(Savepoint 사용).
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
methodB(); // 중첩 트랜잭션 생성
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
// 부모 트랜잭션에 종속적이나 독립적으로 롤백 가능
}
- 사용 예: 부모 트랜잭션 일부를 롤백해야 할 때.
Propagation 요약
- REQUIRED: 기본값으로, 기존 트랜잭션이 있으면 참여하고, 없으면 새 트랜잭션 시작.
- REQUIRES_NEW: 항상 새로운 트랜잭션 시작.
- SUPPORTS: 트랜잭션이 있으면 참여, 없으면 비트랜잭션으로 실행.
- NOT_SUPPORTED: 항상 트랜잭션 없이 실행.
- MANDATORY: 반드시 기존 트랜잭션이 있어야 실행 가능.
- NEVER: 트랜잭션이 있으면 예외 발생.
- NESTED: 부모 트랜잭션에 종속적이나 독립적으로 롤백 가능.
Propagation 선택 기준
- 비즈니스 요구사항에 따라 독립적인 트랜잭션이 필요한지 여부를 판단.
- 성능 고려: 불필요한 새 트랜잭션 생성을 피하기 위해 REQUIRED를 우선적으로 사용.
- 특수 상황: 로그 저장, 비트랜잭션 처리 등은 REQUIRES_NEW, NOT_SUPPORTED 등을 고려.
Propagation은 비즈니스 요구사항과 데이터 무결성을 고려해 적절히 선택해야 합니다.