[Spring]@Transactional사용 시, 참고 사항
스프링 프레임워크에서 트랜잭션 처리 시, transaction annotation을 사용 할 경우 확인해야할 점.
스프링은 @Transactional 을 사용한 클래스에 프록시를 객체를 생성하고, 프록시는 트랜잭션 로직을 메소드 앞뒤에 넣어준다.
프록시 객체는 @Transactional이 포함된 메소드가 호출 될 경우, PlatformTransactionManager를 사용하여 트랜잭션을 시작하고, 정상 여부에 따라 Commit 또는 Rollback 한다.
default는 UnCheckedException 과 Error에 대해서 롤백 정책을 설정된다.
해당 소스에 대해 직접 Exception 클래스를 던져서 예외를 발생시켜서 트랜잭션을 롤백(rollback) 하려고 하면 롤백이 되지 않는다.(try-catch 를 통해서는 롤백이 되지 않음.) 이유는 스프링이 EJB 관습을 따르기 때문이라고 한다.
기본적으로 unchecked exception(RuntimeException)에서만 롤백이 되며, checked exception(IOException, SQLException 등) 에는 롤백이 되지 않는다.
이런 문제로 @Transacional 에는 rollbackFor 옵션이 존재하는데, 아래와 같이 exception을 지정할 수 있다.
@Transactional(rollbackFor = Exception.class)
또한 여러 exception 을 지정할 수도 있수 있고, 롤백 제외 시킬 수도 있다.
[복수의 롤백]
@Transactional(rollbackFro = {RuntimeException.class, Exception.class})[롤백 제외]
@Transactional(noRollbackFor={IgnoreRollbackException.
추가적으로, @Transactional 을 사용한 메소드가 동일한 클래스 내의 다른 메소드에 의해 호출된다면 트랜잭션이 정상 작동하지 않는다.
※ 스프링 기본값으로 사용하는 propagation behavior는PROPAGTION_REQUIRED
이다. 이 옵션을 사용하면 어떤 트랜잭션 안에서 TransactionTemplate을 통해 트랜잭션을 열려고 시도할 경우, AbstractPlatformTransactionManager.getTransaction()는 이미 열려있는 기존 트랜잭션을 반환한다. 즉, 새로운 트랜잭션이 열리는 게 아니라 기존 트랜잭션에 참여하게 된다.
완전히 새롭고 독립적인 트랜잭션을 열기 위해서는 안쪽 트랜잭션의 propagation behavior를 PROPAGATION_REQUIRES_NEW
로 지정해줘야 한다.