Spring의 @Transactional
과 propagation에 대해 알아보자.
(추 후 propagation 관련 예제 코드 추가 예정입니다)
@Transactional
사용 시 Proxy 기반으로 동작하기 때문에 내부 호출에 주의해야 한다.@Transactional
이 걸려있지 않고 메소드를 호출 시 해당 메소드에서 @Transactional
이 걸려있는 호출 대상 메소드는 결론적으로 트랜잭션이 적용되지 않는다는 말임.rollbackFor
옵션을 사용해서 비즈니스 상황에 따라 커밋과 롤백을 선택하면 된다.@Transactional
스프링에서 트랜잭션 처리는 보통 @Transactional
어노테이션을 많이 사용하게 된다.
@Transactional
은 클래스 또는 메소드에 사용할 수 있으며 @Transactional
이 포함된 메소드가 호출될 경우, 프록시 객체가 생성된다.
프록시 객체는 해당 메소드 실행 이전에 PlatformTransactionManager
를 사용하여 트랜잭션을 시작하고 결과에 따라 Commit 또는 Rollback 한다.
@Transactional
우선순위는 어떻게 되는가?@Transactional
은 다음과 같은 우선 순위를 가진다.
단, 주의해야 할 부분이 있다.
@Transactional
어노테이션 같은 경우 Spring AOP를 이용하게 되는데 이 AOP는 기본적으로 Dynamic Proxy를 이용한다. Dynamic Proxy는 인터페이스 기반으로 동작하기 때문에 인터페이스가 없을경우 트랜잭션이 동작하지 않는다.
인터페이스 없이 트랜잭션 동작하게 하려면 CGLib(Code Generation Library) Proxy를 이용하면 된다. CGLib Proxy는 클래스에 대한 Proxy가 가능하기 때문에 인터페이스가 없어도 된다.
@Transactional
은 public method에만 적용된다.@Transactional
은 프록시 기반으로 동작하기 때문에 public method가 아니면 동작하지 않는다.@Transactional
을 적용한다고 하면 IDE에서 컴파일 오류를 확인할 수 있다.@Transactional
이 동작하지 않는다.@Transactional
이 정상적으로 동작하지 않을 것이다.클래스 내 메소드를 호출하여 @Transactional
을 동작하게 하고 싶다면 다음 방법을 고려해보자.
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true, mode = AdviceMode.ASPECTJ)
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
(활용 방안에 관련하여 현재 수정 중)
REQUIRED
가 default논리 트랜잭션의 개념을 도입하여 다음 두 원칙을 생각하자.
외부 롤백이 먼저냐 내부 롤백이 먼저냐의 순서에 따라 전체 트랜잭션(물리 트랜잭션)의 롤백이 어떻게 달라지는지 확인해봐야 한다. 이는 전파 옵션에 따라서도 다르다. 실무에서 대부분은 default 값을 사용하고 아주 가끔 REQUIRES_NEW
를 사용하며 나머지는 거의 사용하지 않는다.
기존 트랜잭션이 없으면 생성, 있으면 참여한다. 트랜잭션이 필수라는 의미로 이해하자.
항상 새로운 트랜잭션을 생성한다.
트랜잭션을 지원한다. 기존 트랜잭션이 없으면 없는대로 진행하고 있으면 참여한다.
트랜잭션 지원 x
의무사항이다. 반드시 트랜잭션이 있어야 한다.
기존 트랜잭션이 없는 경우 IllegalTransactionStateException
발생
트랜잭션을 사용하지 않는다는 의미다. 기존 트랜잭션이 있으면 예외 발생.
isolation
, timeout
, readOnly
는 트랜잭션이 처음 시작될 때만 적용 o