트랜잭션 분리를 통한 서로 다른 서비스 간의 의존성 줄이기

Louie·2023년 3월 28일
0

프로젝트

목록 보기
2/6

서론

저번 포스팅에는 @EventListener를 통해 서로 다른 서비스 간의 의존성을 줄였습니다.

이번에는 트랜잭션을 분리하게 된 문제 상황과 방법을 정리해보겠습니다.

문제 상황

public class BoardService {

	private final ApplicationEventPublisher publisher;

	@Transactional
	public void register() {
	    // 게시글 등록 로직(생략)

	    // 게시글 등록 이벤트 발행
		publisher.publishEvent(new BoardRegisterEvent());
	}
}
public class NotificationEventListener {

    @EventListener
    public void registerKeywordNotification(BoardRegisterEvent event) {
        // 키워드 알림 생성 로직 중 예외 발생
    }

}

위 코드에서 BoardRegisterEvent가 발행되어 키워드 알림 생성 로직이 실행되는 도중 RuntimeException이 발생한다고 가정하겠습니다.

스프링은 기본적으로 RuntimeException이 발생한 경우 트랜잭션을 롤백하기 때문에 키워드 알림이 생성되지 않고 롤백이 될 것입니다.

하지만 여기서 게시글 등록과 키워드 알림 생성 로직이 동일한 트랜잭션에서 실행되기 때문에 게시글 등록이 되지 않습니다.

따라서 게시글 등록 로직이 키워드 알림 생성 로직에 대해 영향을 받는 문제가 발생합니다.

해결 방안

트랜잭션 전파라고 불리는 @Transactionalpropation 옵션을 활용하여 문제 상황에서 나온 두 로직을 별도의 트랜잭션으로 분리할 수 있습니다.

트랜잭션 전파는 따로 설정하지 않는 경우 기본값으로 Propagation.REQUIRED가 적용됩니다.

Propagation.REQUIRED는 실행 시점에 이미 트랜잭션이 존재하는 경우 해당 트랜잭션에 참여하고 트랜잭션이 존재하지 않는 경우 새로운 트랜잭션을 시작합니다.

따라서 위 다이어그램과 같이 키워드 알림 생성 로직에서는 게시글 등록 메서드에서 생성된 트랜잭션 A에 참여하게 되어 게시글 등록과 키워드 알림 생성이 동일한 트랜잭션에서 실행됐습니다.

Propagation.REQUIRES_NEW

Propagation.REQUIRES_NEW는 트랜잭션 전파 옵션 중 하나로 트랜잭션 존재 여부에 상관 없이 새로운 트랜잭션을 시작합니다.

따라서 해당 옵션을 사용하면 위 다이어그램과 같이 키워드 알림 생성 시점에 게시글 등록에서 실행됐던 트랜잭션에 참여하는 것이 아닌 별도의 트랜잭션을 시작하도록 구현할 수 있습니다.

결론

public class NotificationEventListener {

	@Transactional(propagation = Propagation.REQUIRES_NEW)
    @EventListener
    public void registerKeywordNotification(BoardRegisterEvent event) {
        // 키워드 알림 생성 로직
    }

}

위와 같이 트랜잭션 전파 옵션을 변경하여 게시글 등록과 키워드 알림 생성에 대한 트랜잭션을 분리할 수 있었습니다!

profile
백엔드 개발자를 준비하고 있는 Louie입니다.

0개의 댓글