다른 사람의 코드 리뷰를 보던 도중 작성한 코드대로라면 정상적으로 롤백될 것 같지 않아 @Transaction
어노테이션의 롤백 옵션에 대해 알아보게 되었습니다.
@Transaction
어노테이션 롤백 설정Defines zero (0) or more exception types, which must be subclasses of Throwable, indicating which exception types must cause a transaction rollback.
By default, a transaction will be rolled back on RuntimeException and Error but not on checked exceptions (business exceptions). See DefaultTransactionAttribute.rollbackOn(Throwable) for a detailed explanation.
This is the preferred way to construct a rollback rule (in contrast to rollbackForClassName()), matching the exception type and its subclasses in a type-safe manner. See the class-level javadocs for further details on rollback rule semantics.
공식문서
rollbackFor
옵션을 별도로 설정하지 않으면 RuntimeException
과 Error
가 발생했을 때는 롤백을 하지만 checked exception
이 발생했을 때는 롤백을 하지 않는다고 합니다.
이때 checked exception
에 대해서 처음 들어보게 되어서 어떤 예외인지 조금 더 살펴보고 싶었습니다.
kotlin에서는 throwable을 확장해 사용자에게 문제 상황을 알리는 종류 세 가지가 존재합니다.
프로그램 실행 중 비정상적인 상황이 발생했음을 알려줍니다.
대표적인 예로 StackOverflowError
, OutOfMemoryError
가 있습니다.
모두 Error 클래스를 확장합니다.
프로그래머가 catch 구문을 통해 별도의 핸들링을 할 수 없는 상황에서 발생하게 됩니다.
더 이상 프로그램을 실행해도 무의미하거나 더 안 좋은 상황으로 이어질 수 있을 때 발생합니다.
대표적인 예로 IllegalArgumentException
, IllegalStateException
이 있습니다.
모두 RuntimeException
을 확장합니다.
에러와의 차이점은 프로그래머가 문제 상황이 발생했음을 인지한 구간에서 직접 예외를 던질 수 있다는 점입니다.
대표적인 예로 IOException
, SQLException
이 있습니다.
비검사 예외와 거의 동일하나 Exception
클래스를 확장합니다. 정확히 얘기하면 RuntimeException
을 확장하지 않습니다.
해당 예외를 핸들링 해 복구 전략을 수행할 수 있을 때 사용합니다. 호출하는 쪽에 반드시 해당 예외에 대한 복구 전략을 세워놓는 것을 강제한다고 볼 수 있습니다.
기본적으로 Transactional에서 문제가 발생했을 때 Error와 RuntimeException과 이의 하위 클래스들에 해당하는 것들만 롤백의 대상으로 취급하는 이유는 호출하는 쪽에서 복구 전략을 세울 수 없는 상황이기 때문입니다.
반대로 검사 예외의 경우, 호출하는 쪽에서 충분히 문제 상황에 대해 복구할 수 있는 상황에 던져지는 예외이기 때문에 롤백의 대상으로 삼지 않고 호출하는 쪽에 예외의 핸들링 책임을 전담합니다.