스프링

스프링 - 트랜잭션 이해 (2)

개발자 포비 2024. 12. 13. 11:47

Spring 트랜잭션의 이해

1. 트랜잭션 동작 원리

  • Spring의 트랜잭션은 프록시를 통해 작동
  • @Transactional이 선언된 메서드 호출 시, 트랜잭션 프록시가 먼저 개입
[Client] -> [@Transactional Method]
              |
              v
    [Transaction Proxy]
         |
         v
    [Real Method]

2. 트랜잭션 동기화 매니저

  • ThreadLocal을 사용하여 트랜잭션 정보 관리
  • 각 스레드별로 독립적인 트랜잭션 관리
    // TransactionSynchronizationManager
    private static final ThreadLocal<Map<Object, Object>> resources;
    private static final ThreadLocal<String> currentTransactionName;

3. 내부/외부 트랜잭션

                        [Transaction Flow]

    [Outer Transaction]  -->  [Inner Transaction]
    (신규 트랜잭션 O)         (신규 트랜잭션 X)

    1. 트랜잭션 시작          7. 트랜잭션 존재 확인
    2. 커넥션 획득           8. 기존 트랜잭션 참여
    3. autoCommit(false)     9. 로직 실행
    4. 커넥션 보관           
    5. 로직 실행             
                   [Transaction Synchronization Manager]
                   (ThreadLocal Storage에서 관리)

4. 트랜잭션 전파

  • REQUIRED (기본값)
    • 외부 트랜잭션 있으면: 참여
    • 없으면: 새로 생성
  • REQUIRES_NEW
    • 항상 새로운 트랜잭션 생성
    • 물리적으로 독립된 트랜잭션
[REQUIRED]                      [REQUIRES_NEW]

T1 시작                         T1 시작
  └─ T2 (T1에 참여)              └─ T2 (새로운 트랜잭션)
                                    (T2 완료 후 T1 재개)

5. 물리/논리 트랜잭션

  • 물리 트랜잭션: 실제 DB 커밋/롤백 단위
  • 논리 트랜잭션: 트랜잭션 매니저가 관리하는 단위
[REQUIRED 예시]
논리1 ─┐
논리2 ─┼─ 하나의 물리 트랜잭션
논리3 ─┘

[REQUIRES_NEW 예시]
논리1 = 물리1
논리2 = 물리2
논리3 = 물리3

6. 주의사항

  • 같은 클래스 내부 호출: 트랜잭션 적용 안됨
  • private 메서드: @Transactional 동작 안함
  • RuntimeException: 기본적으로 롤백
  • Checked Exception: 기본적으로 롤백 안함

7. 해결방법

// 1. 다른 클래스로 분리
@Service
class ServiceA {
    private ServiceB serviceB;

    @Transactional
    public void methodA() {
        serviceB.methodB(); // 트랜잭션 적용
    }
}

// 2. self 주입
@Service
class Service {
    @Autowired
    private Service self;

    @Transactional
    public void methodA() {
        self.methodB(); // 트랜잭션 적용
    }
}