728x90
반응형

하나의 Controller 메소드 안에서 Service를 여러 개 호출 할 때,
일부는 @Transactional 가 있고, 일부는 없으면 어떻게 될까?


각각 독립된 트랜잭션으로 동작해요!

Controller에 @Transactional이 없으면, 묶어줄 부모 트랜잭션이 없으니까 Service들이 각자 자기 트랜잭션을 생성하고 끝내요.

Controller (트랜잭션 없음)
    │
    ├─→ ServiceA @Transactional  → 트랜잭션 A 시작 → 커밋 ✅ (완전히 끝남)
    │
    ├─→ ServiceB @Transactional  → 트랜잭션 B 시작 → 커밋 ✅ (완전히 끝남)
    │
    └─→ ServiceC (없음)          → 그냥 실행 (트랜잭션 없이)

문제가 생기는 상황

// Controller
public void controllerMethod() {
    serviceA.save();     // @Transactional - 커밋 완료 ✅
    serviceB.save();     // @Transactional - 커밋 완료 ✅
    serviceC.doSomething(); // @Transactional 없음

    // 💥 여기서 예외 발생!!
}
serviceA → 이미 커밋됨, 롤백 ❌ 불가
serviceB → 이미 커밋됨, 롤백 ❌ 불가
serviceC → 트랜잭션 없으니 롤백 개념 자체가 없음

→ 데이터 불일치 발생! 💀

해결책

이 세 개를 하나의 트랜잭션으로 묶고 싶으면 감싸는 Service를 만들어요.

// Controller
public void controllerMethod() {
    wrapperService.doAll(); // 여기만 호출
}

// WrapperService (또는 기존 Service 중 하나에 합치기)
@Transactional // 얘가 트랜잭션 시작
public void doAll() {
    serviceA.save();        // 같은 트랜잭션 참여
    serviceB.save();        // 같은 트랜잭션 참여
    serviceC.doSomething(); // 같은 트랜잭션 참여

    // 여기서 예외나면 셋 다 롤백 ✅
}

핵심 정리

상황 동작

Controller @Transactional O 전부 하나로 묶임
Controller @Transactional X Service마다 각자 트랜잭션
중간에 예외 발생 이미 커밋된 건 롤백 불가 💀

여러 Service를 하나의 작업단위로 묶어야 한다면, 반드시 상위에 @Transactional이 있는 레이어가 하나 있어야 해요.

728x90
반응형

+ Recent posts