본문 바로가기

Backend/Spring

@Transactional 전파 전략

Spring 프레임워크에서는 @Transactional 어노테이션을 사용하여 데이터베이스 트랜잭션을 쉽게 처리할 수 있습니다. 이 글에서는 Spring에서 제공하는 @Transactional 어노테이션의 전파 전략에 대해 알아보고, 코드 예시를 통해 각 전략의 동작 방식을 살펴봅니다. 또한, @Async 어노테이션과 함께 사용되는 경우에 대해서도 설명합니다.

Transactional 전파 전략

  1. Propagation.REQUIRED (기본 전략): 현재 진행 중인 트랜잭션이 있으면 해당 트랜잭션에 참여하고, 없으면 새로운 트랜잭션을 시작합니다.
  2. Propagation.REQUIRES_NEW: 항상 새로운 트랜잭션을 시작하고, 현재 진행 중인 트랜잭션 (있는 경우)은 일시 중단합니다.
  3. Propagation.SUPPORTS: 현재 진행 중인 트랜잭션이 있으면 해당 트랜잭션에 참여하고, 없으면 트랜잭션 없이 실행됩니다.
  4. Propagation.MANDATORY: 현재 진행 중인 트랜잭션이 있으면 해당 트랜잭션에 참여하며, 없으면 예외가 발생합니다 (IllegalTransactionStateException).
  5. Propagation.NEVER: 트랜잭션이 없어야 메소드를 실행하며, 현재 진행 중인 트랜잭션이 있으면 예외가 발생합니다 (IllegalTransactionStateException).
  6. Propagation.NOT_SUPPORTED: 현재 진행 중인 트랜잭션이 있으면 일시 중단하고, 트랜잭션 없이 메소드를 실행합니다.
  7. Propagation.NESTED: 현재 진행 중인 트랜잭션이 있으면 중첩 트랜잭션을 시작하며, 없으면 Propagation.REQUIRED와 동일하게 동작합니다. 중첩 트랜잭션은 하나의 큰 트랜잭션에 속하지만, 부분적으로 커밋 또는 롤백이 가능합니다. 중첩 트랜잭션이 롤백되면, 외부 트랜잭션은 계속 진행됩니다.

이러한 전파 전략들은 @Transactional 어노테이션에 다음과 같이 propagation 속성을 통해 지정할 수 있습니다.

@Service
public class MyService {

    @Transactional
    public void methodA() {

                ...

        methodB();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void methodB() {

                ...

        }
}

@Async와 함께 사용되는 경우

@Async 어노테이션은 메소드를 비동기적으로 실행하게 합니다. @Async@Transactional이 함께 사용되면, 기본 전파 전략인 Propagation.REQUIRED가 적용되지만, 비동기 메소드는 다른 스레드에서 실행되기 때문에 호출하는 쪽의 트랜잭션과 독립적으로 동작하게 됩니다. 이 경우, 비동기 메소드에서 새로운 트랜잭션을 시작하게 됩니다.

예를 들어, 다음과 같은 코드가 있을 때:

@Service
public class MyService {

    @Async
    @Transactional
    public void asyncMethod() {

                ...

    }
}

asyncMethod는 비동기적으로 실행되며, 새로운 트랜잭션을 시작합니다. 호출하는 쪽의 트랜잭션과 독립적으로 동작하므로, 호출하는 쪽의 트랜잭션 상태에 영향을 주지 않습니다. 이 말은, 호출하는 쪽의 트랜잭션은 비동기 메소드의 종료 여부와 상관 없이 커밋될 수 있다는 것을 의미합니다.

비동기 메소드가 끝나기 전에 호출하는 쪽의 트랜잭션이 커밋되더라도, 비동기 메소드의 트랜잭션은 계속 진행되며, 해당 작업이 완료되면 커밋되거나 롤백됩니다. 이렇게 되면 서로 다른 스레드에서 독립적으로 실행되는 트랜잭션을 관리할 수 있습니다.