Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

che01 님의 블로그

트랜잭션 - 롤백 정책, 전파, 이벤트 리스너 본문

카테고리 없음

트랜잭션 - 롤백 정책, 전파, 이벤트 리스너

che01 2025. 6. 26. 19:30

트랜잭션 롤백 정책

트랜잭션에서 어떤 예외가 발생했을 때 롤백을 진행할지 결정하는 정책입니다.

예외 종류 복습

  • 체크예외(Exception): 컴파일 시점에 처리해야 하는 예외
  • 언체크예외(RuntimeException): 런타임에 발생하는 예외

기본 롤백 정책

스프링에서는 기본적으로 RuntimeException이 발생했을 때만 rollback을 진행합니다. 체크예외는 기본적으로 rollback하지 않습니다.

롤백 정책 설정

rollbackFor

  • 특정 예외를 rollback 정책에 추가할 때 사용
  • 체크예외도 rollback 대상으로 만들 수 있음

noRollbackFor

  • 특정 예외를 rollback 정책에서 제거할 때 사용
  • RuntimeException이어도 rollback하지 않도록 설정 가능
@Transactional(rollbackFor = Exception.class)
public void methodWithRollbackFor() {
    // 체크예외도 rollback 대상
}

@Transactional(noRollbackFor = RuntimeException.class)
public void methodWithNoRollbackFor() {
    // RuntimeException이어도 rollback하지 않음
}

트랜잭션 전파

이미 진행 중인 트랜잭션이 있을 때 새로운 트랜잭션을 어떻게 처리할지 결정하는 정책입니다.

주요 전파 정책

REQUIRED (기본값)

  • 기존 트랜잭션이 있으면 참여하고 없으면 새로 시작
  • 가장 일반적으로 사용되는 정책

REQUIRES_NEW

  • 항상 새로운 트랜잭션을 시작
  • 기존 진행 중인 트랜잭션은 잠시 보류
  • 자식 트랜잭션이 완료되면 부모 트랜잭션 재개

SUPPORTS

  • 이미 트랜잭션이 있으면 참여, 없으면 트랜잭션 없이 진행

NESTED

  • REQUIRES_NEW와 비슷하지만 부모 트랜잭션이 rollback되면 자식도 함께 rollback

NEVER

  • 트랜잭션이 존재하면 예외 발생

실습 시나리오: 수강신청

수강신청 과정에서 로깅 실패 시 전체 트랜잭션이 rollback되는 것이 적절한지 고민해봐야 합니다. 로깅은 부가 기능이므로 REQUIRES_NEW를 사용하여 별도 트랜잭션으로 처리하는 것이 좋습니다.

@Transactional
public void registerCourse() {
    // 수강신청 로직
    courseService.register();
    
    // 로깅은 별도 트랜잭션으로 처리
    loggingService.log();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void log() {
    // 로깅 로직
}

트랜잭션 이벤트 리스너

트랜잭션의 특정 시점에 이벤트를 처리할 수 있는 기능입니다. 성공 시에만 로깅을 남겨야 하는 요구사항에 유용합니다.

이벤트 리스너 종류

BEFORE_COMMIT

  • 트랜잭션 커밋 전에 실행

AFTER_COMMIT

  • 트랜잭션 커밋 후에 실행
  • 성공적으로 완료된 후 처리할 작업에 적합

AFTER_ROLLBACK

  • 트랜잭션이 롤백되었을 경우 실행

AFTER_COMPLETION

  • 커밋 또는 롤백이 끝난 후 실행

구현 방법

  1. 서비스에 ApplicationEventPublisher 의존성 추가
  2. 이벤트 클래스 생성
  3. 이벤트 리스너 생성
  4. 이벤트 발행 로직 추가
@Service
public class CourseService {
    private final ApplicationEventPublisher eventPublisher;
    
    @Transactional
    public void registerCourse() {
        // 수강신청 로직
        
        // 이벤트 발행
        eventPublisher.publishEvent(new CourseRegisteredEvent());
    }
}

@Component
public class CourseEventListener {
    
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void handleCourseRegistered(CourseRegisteredEvent event) {
        // 트랜잭션 성공 후 로깅
        log.info("수강신청이 성공적으로 완료되었습니다.");
    }
}

이벤트 리스너를 사용하면 트랜잭션의 결과에 따라 적절한 후처리를 할 수 있으며, 비즈니스 로직과 부가 기능을 깔끔하게 분리할 수 있습니다.