프로그래밍/Spring

[Spring] @Transactional 롤백은 언제 되는 걸까? - 예외가 발생했는데도 DB 반영이 된다고?

Jay22 2019. 11. 10. 16:54
반응형

@Transactional 애노테이션

스프링은 @Transactional 애노테이션이 붙은 클래스에 프록시를 생성합니다. 프록시는 트랜잭션 로직을 메서드 앞뒤에 넣어줍니다.

이 글은 @Transactional 의 롤백에 대해서 다룹니다. rollbackFor이라는 것을 써보면서 어디에 어떻게 적용되는지 알아보겠습니다.

 

책 정보를 저장하는 아주 간단한 코드입니다.

 

책 저장 Controller

 

다음은 책을 저장하는 메서드입니다. @Transactional 애노테이션의 rollbackFor 속성에 대해서 RuntimeException.class를 등록했습니다.

이 애노테이션은 스프링에게 런타임 예외가 발생한다면 롤백을 하라고 말합니다.

 

rollbackFor 설정

그렇다면 rollbackFor 속성을 주지 않는다면 어떻게 될까요?

 

사실은 스프링은 디폴트로 UnCheckedExceptionError에 대해서 롤백 정책을 설정합니다. 헷갈리나요?

예시를 다시 살펴볼게요.

 

다음과 같이 @Transactional에 아무 속성을 주지 않는다면

 

기본적인 @Transactional 애노테이션

스프링이 다음과 같이 이해합니다.

 

스프링이 이해하는 @Transactional

스프링은 RuntimeException 과 Error를 기본적으로 롤백 정책으로 이해합니다.

 

(CheckedException, UnCheckedException, Error에 대해서 구분을 하지 못하시는 분들은 예외에 대해서 숙지를 하시고 보시면 될 것 같습니다.)

 

하지만 이런식으로 checked 예외를 던져서 catch로 처리했다고 가정합시다. (catch로 처리하든 안 하든 결과는 같음)

 

CheckedException 을 처리했다면?

이런 경우는 롤백이 기본적으로 되지 않습니다. 결국 데이터베이스에는 값이 들어가게 된 상태로 끝나게 됩니다.

다시 말하면 모든 예외상황에서 롤백이 되는 것이 아니라는 것입니다.

앞서 설명드린 것처럼 catch 를 하지 않고 상위로 throw를 해도 마찬가지로 롤백이 되지 않습니다.

 

직접 postman으로 요청을 보내면서 확인해보죠.

 

요청

 

예외가 발생했음에도 (Checked Exception) 데이터베이스에 값이 들어간 모습입니다.

 

데이터베이스 반영

 

참고로 NullPointerException 은 RuntimeException (UnCheckedException) 이기 때문에 디폴트로 롤백이 됩니다.

rollbackFor은 그럼 언제쓰나요?

먼저 스프링이 RuntimeException을 관리하는 것을 잊지 않는 게 중요합니다. 만약에 Checked Exception 이 발생했을 때 트랜잭션이 롤백이 되지 않고 디비에 변경이 되는 것을 모르고 있을 때가 문제가 됩니다. 모든 예외에 대해서 전부 트랜잭션을 롤백하고 싶다면

rollbackFor = {Exception.class}

으로 설정을 해야 롤백이 됩니다.

결론은 롤백이 언제 되는지 정확히 파악하고 애플리케이션에 맞게 설정을 하는 것이 좋겠죠.

 

참고:

https://netsurfingzone.com/spring/transactional-rollbackfor-example-using-spring-boot

반응형