1. 상황
프로젝트 도중 @Transactional을 선언했음에도 불구하고, 해당 메서드가 실행 도중 exception이 발생하였을 때 rollback이 일어나지 않는 문제가 발생하였습니다. 이를 계기로, @Transactional에 사용법에 대해 학습한 내용을 정리하려 합니다. 아래 링크는 해당 이슈에 대한 github 링크입니다.
https://github.com/pythaac/mamacoco/issues/4
2. 트랜잭션의 Propagation
트랜잭션의 Propagation은 트랜잭션 내에서 트랜잭션이 다시 호출되어 중첩되었을 때, 이를 처리하는 방법을 다루고 있습니다. 제가 확인해본 방식은 REQUIRED, REQUIRES_NEW, MANDATORY, NESTED 총 4가지 입니다.
REQUIRED (default)
REQUIRED는 자식 트랜잭션이 부모 트랜잭션으로 합쳐지는 방식입니다. 즉, 부모 트랜잭션이 있다면 부모 트랜잭션만 있는 것과 같습니다.
REQUIRES_NEW
REQUIRES_NEW는 새로운 트랜잭션을 생성합니다. 두 트랜잭션은 독립적으로 취급되며, 따라서 COMMIT과 ROLLBACK도 서로 영향을 주지 않습니다.
MANDATORY
MANDATORY는 부모 트랜잭션을 필요로 합니다. 부모 트랜잭션이 없다면 exception이 발생합니다.
NESTED
NESTED는 중첩된 트랜잭션으로, exception 위치에 따라 ROLLBACK의 정도가 달라집니다. SAVEPOINT와 같은 기능으로, 지정된 상태까지 ROLLBACK합니다.
위 이슈를 다루면서 제가 원하는 결과는 NESTED였고, 여러 Propagation을 테스트해보았지만 REQUIRED만 동작하는 것으로 확인되었습니다. StackOverflow[1]에서는 MySQL이 Nested transaction을 지원하지 않는다고 이야기하고 있고, 5.7 버전 document[2]에서도 트랜잭션이 nested되지 않는다고 나와있으며, 8.0 버전 document[3]에서는 SAVEPOINT가 Nested transaction을 구현할 수 있다고 나와있습니다. 따라서 현재까지 확인한 바로는 MySQL에서 NESTED를 사용할 수 없는 것 같습니다.
3. @Transactional 사용시 주의사항
위 이슈를 다루면서, Transaction이 rollback되지 않고, CrudRepository의 delete 함수에서 ClassCastException이 발생하는 등 여러 문제가 발생하였습니다. 이를 통해서 @Transactional을 사용할 때 필수적으로 알아야할 사항들을 정리해보았습니다.
- Spring Bean이 해당 메서드를 호출
- public 메서드
- 한 클래스에서 @Transactional이 아닌 메서드가 @Transactional 메서드 호출
StackOverflow[6]에 의하면 @Transactional 메서드 호출시 aspect로 감싸 호출하기 때문에 해당 메서드는 public이며 Spring Bean이 호출해야합니다. 또한 Spring bean이 호출한다 해도, 호출하는 메서드에 @Transactional이 없으면 Rollback이 일어나지 않습니다. @Transactional 메서드를 직접 호출하도록 설계해야합니다.
[1] https://stackoverflow.com/questions/1306869/are-nested-transactions-allowed-in-mysql
[2] https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html
[3] https://dev.mysql.com/doc/refman/8.0/en/glossary.html
[4] https://deveric.tistory.com/86
[5] https://jsonobject.tistory.com/467
[6] https://stackoverflow.com/questions/16522412/transactional-rollback-not-working
[7] https://blog.naver.com/PostView.naver?blogId=varkiry05&logNo=221617256419
'프레임워크 > Spring' 카테고리의 다른 글
[Spring] Spring AOP (Aspect-Oriented Programming) (0) | 2022.04.19 |
---|---|
[Spring] JpaRepository의 delete (0) | 2022.04.04 |
[인프런][스프링 입문] 25~27 강 (0) | 2022.03.09 |
[인프런][스프링 입문] 21~24강 (0) | 2022.03.08 |
[인프런][스프링 입문] 17~20 강 (0) | 2022.03.05 |