@Transactional과static

김승환·2024년 3월 24일
1

Spring

목록 보기
3/3

문제 상황

@DataJpaTest를 적용하고 @BeforeAll을 이용하여 테스트 전 공통적인 행동을 정의하려고 했는데, 테스트를 두 번 진행하게 되면 데이터베이스 정합성 문제가 발생하는 에러가 발생하였습니다.이유는 unique여야 하는 id값이 중복되었기 때문이었어요. 하지만 첫 테스트 시에는 데이터베이스 정합성 문제가 발생하지 않아 데이터베이스를 확인하였습니다.
@DataJpaTest를 이용해 @Transactional이 적용되어 데이터베이스 롤백이 진행되어야 했지만, 진행되지 않아 테스트를 다시 실행하게 되면 같은 유저가 다시 저장되는 문제가 발생하는 것이었습니다.

배경

그렇다면, 왜 @Transactional을 이용한 데이터베이스 롤백이 진행되지 않은 것일까요?

스프링에서 @Transactional은 AOP로 구현됩니다.
@Transactional을 사용하기 위해서는 스프링이 프록시 객체를 만들어서 구현합니다.
그리고 Junit의 @BeforAll은 무조건 static 메소드로 구현되어야 합니다.

문제의 원인

여기서 Static 메서드에 대한 프록시는 만들 수 없다는 사실이 문제의 원인이었습니다.
Java에서 static 키워드를 사용한다는 것은 메모리에 한번 할당되어 프로그램이 종료될 때 해제되는 것을 의미합니다.
static 변수와 static 메소드는 객체가 생성되기 이전에 이미 메모리 영역에 할당되어 있습니다. 그렇기 때문에 객체의 생성 없이 바로 접근할 수 있습니다.

프록시 객체를 만드려면 호출된 객체의 바이트코드를 조작해서 만드는데 static은 객체 생성 없이 바로 접근하는 것이므로 불가능했던 것입니다.

느낀점

@Transactional이 DB를 무조건적으로 이전으로 롤백해주지 않는다는 것을 깨달았습니다.
Test를 작성할 때 @Transactional의 범위를 잘 파악하고 사용해야 하며 @Transactional이 프록시 객체를 기반으로 작동한다는 원리를 알 수 있었습니다.

@Transactional에 대한 토비님의 좋은 글이 있어서 가져오면서 마무리하도록 하겠습니다!

0개의 댓글