diff --git a/docs/adr/ADR-003-transaction-boundary.md b/docs/adr/ADR-003-transaction-boundary.md new file mode 100644 index 0000000..ef40a37 --- /dev/null +++ b/docs/adr/ADR-003-transaction-boundary.md @@ -0,0 +1,119 @@ +# ADR-003: 트랜잭션 경계(Transaction Boundary) 정의 + +## Context + +Spring에서 트랜잭션 경계 설정 방식에 따라: +- 데이터 무결성 보장 +- 성능 최적화 +- 격리 수준(Isolation Level) 제어 + +를 적절히 balancing해야 한다. + +## Decision + +### 1. 트랜잭션 전파 정책 + +| 전파 유형 | 사용 시점 | +|----------|----------| +| `REQUIRED` (기본값) | 대부분의 Service 메서드 | +| `REQUIRES_NEW` | 독립적인 작업 단위 (로깅, 알림) | +| `NESTED` | 저장점(savepoint) 기반 부분 롤백 | +| `SUPPORTS` | 읽기 전용 조회 (트랜잭션 없으면 자동 읽기 전용) | + +### 2. 격리 수준(Isolation Level) + +```java +@Transactional(isolation = Isolation.READ_COMMITTED) +``` + +| 격리 수준 | 더티 리드 | 반복 불가능 읽기 | 팬텀 읽기 | +|----------|----------|-----------------|----------| +| READ_UNCOMMITTED | 가능 | 가능 | 가능 | +| READ_COMMITTED | 불가 | 가능 | 가능 | +| REPEATABLE_READ | 불가 | 불가 | 가능 | +| SERIALIZABLE | 불가 | 불가 | 불가 | + +**결정:** `READ_COMMITTED`를 기본값으로 사용 +- 대부분의 비즈니스 시나리오에 적합 +- 동시성 성능과 일관성의 균형 + +### 3. 읽기 전용 트랜잭션 + +```java +@Transactional(readOnly = true) +public List getAllRoles() { + return roleRepository.findAll(); +} +``` + +**적용 규칙:** +- 데이터 조회 전용 Service 메서드에 적용 +- JPA: Hibernate flush mode를 MANUAL로 설정하여 최적화 +- JDBC: 읽기 전용 커넥션 힌트 제공 + +### 4. 트랜잭션 경계 위치 + +``` +[Controller] + ↓ +[Service Layer] ← ★ 트랜잭션 경계 + ↓ +[Repository Layer] + ↓ +[Database] +``` + +**규칙:** +- 트랜잭션은 Service 계층에서 시작 +- Controller에서 @Transactional 사용 금지 +- Repository에서 @Transactional 사용 금지 + +### 5. 롤백 정책 + +```java +@Transactional(rollbackFor = Exception.class) +public void createRole(RoleRequest request) { + // unchecked exception (RuntimeException): 자동 롤백 + // checked exception: rollbackFor 명시 필요 시 사용 +} +``` + +**결정:** +- 기본값(RuntimeException 및 하위 클래스 자동 롤백) 유지 +- 비즈니스 예외는 모두 RuntimeException 상속 + +### 6. 트랜잭션 타임아웃 + +```java +@Transactional(timeout = 30) // 30초 +``` + +**적용 규칙:** +- 대량 데이터 처리 배치 작업에만 명시적 타임아웃 설정 +- 일반 API 요청은 기본값(INFINITE) 유지 + +## Alternatives + +### 대안 1: Programmatic Transaction +- TransactionTemplate 사용 +- 단점: 코드 복잡성 증가, AOP 이점 상실 +- 채택하지 않음 (선언적 트랜잭션 채택) + +### 대안 2: Controller 레벨 트랜잭션 +- 단점: HTTP 요청 단위로 전체 트랜잭션 시야 과도 +- 채택하지 않음 + +## Consequences + +**Positive:** +- Service 메서드 단위로 명확한 트랜잭션 경계 +- 격리 수준 및 전파 정책 세밀한 제어 가능 +- 읽기 전용 최적화 활용 가능 + +**Negative:** +- 잘못된 전파 설정 시 예상 외 동작 가능 +- 다중 데이터소스 환경에서 복잡성 증가 + +**Mitigation:** +- 전파 정책 사용 시 주석으로 의도 명시 +- Integration Test에서 트랜잭션 동작 검증