순간을 성실히, 화려함보단 꾸준함을

@Transactional 은 mySql 의 auto_increment 값을 롤백시켜주지 않는다고요?! 본문

나의 개발 메모장

@Transactional 은 mySql 의 auto_increment 값을 롤백시켜주지 않는다고요?!

폭발토끼 2023. 3. 11. 13:35

안녕하세요. 폭발토끼입니다.
오늘은 글또 3번째 글을 작성하는 날입니다!!

오늘 다뤄볼 주제는 spring 을 사용하고 있으시면 test code 를 작성할때 한번쯤은 마주해봤을 내용을 가져왔습니다.

 

바로 auto_increment 에 관한 내용입니다.

테스트 코드를 작성하는 법에 대해서 공부하던 중에 테스트 하나만 진행했을때는 문제없이 성공했지만 두개 이상의 테스트를 진행했을 경우에 이상하게 자꾸 에러가 발생하는 문제가 생겼었습니다.

Member Entity 입니다. 기본키 전략을 IDENTITY 로 설정해주었습니다.

간단한 회원가입 Controller 를 테스트 하는 코드입니다. Member 테이블에 save 하면 기본키가 1씩 증가하게 되겠죠?

회원정보 수정 Controller 를 테스트 하는 코드입니다. 마찬가지로 Member 객체를 생성하고 save 하게 되면 member 테이블에 기본키가 1이 증가한 값이 들어가게 될 것 입니다.

각각 테스트를 따로 돌려보겠습니다.

두 테스트 모두 문제없이 성공하는 것을 볼 수 있습니다.
그럼 이번에는 한꺼번에 돌려보겠습니다.

하나의 테스트만 성공하고 나머지 하나는 실패한걸 볼 수 있죠??
이유가 대체 뭘까요??분명히 메소드마다 @Transactional 어노테이션을 붙여줬으면 테스트가 끝나고 롤백이 되어야 하는게 맞는데 말이죠....

바로 이 부분에 대해서 크게 착각을 하고 있었던 것 입니다.
사실 mySql 에서 auto_increment 속성은 @Transcational 어노테이션과 관계없이 원래 롤백이 되지 않기 때문입니다.

 

왜 롤백 대상이 아닐까요? 바로 데이터의 정합성 때문입니다.

 

예시를 하나 들겠습니다.

1번 세션에서 테이블 A 에 데이터를 insert 했습니다.
2번 세션에서 테이블 A 에 데이터를 insert 했습니다.
2번 세션에서 테이블 A 의 pk 값을 테이블 B에 fk 로 잡아 insert 하였습니다.
2번 세션에서 commit 을 진행합니다.
1번 세션에서 rollback 을 실행합니다.

 

이런상황에서 2번세션에서 commit 했을때의 기본키의 값을 1번 세션에서 rollback을 진행했다는 이유로 나머지 데이터들의 pk 값들을 rollback 시켜야 될까요? 그럼 fk 를 가지고 있는 테이블B 에 들어가 있는 값은 어떻게 수정해줄까요???

이런 문제점들 때문에 auto_increment 는 rollback 의 대상에서 제외되는 것 입니다.

 

자 그럼 우린 지금까지 내용으로 mysql 의 auto_increment 전략은 롤백이 되지 않는구나! 라는걸 알았습니다.
그러면 테스트 코드를 대체 어떻게 짜야할까요???

 

첫번째 방법은 테스트를 시작하기 전에 매번 auto_increment 의 값을 1로 초기화위와 같이 테스트를 시작하기 전에 매번 auto_increment 값을 1로 초기화 해주면 됩니다. 그러나 이 방법에는 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 를 사용하면 정상적으로 적용이 되지 않습니다.
그 이유는 https://kth990303.tistory.com/371 이 블로그를 참고해보세요!

@BeforeEach 
void clean(){ 
    this.entityManager .createNativeQuery("ALTER TABLE MEMBER AUTO\_INCREMENT = 1") .executeUpdate(); 
}

위와 같이 말이죠.

두번째 방법은 auto_increment 에 의존하지 않고 직접 save한 객체를 조회해서 테스트에 적용하는 것 입니다.

위와 같이 소스를 수정하고 한꺼번에 테스트를 돌려보도록 하겠습니다.

짠~ auto_increment 를 초기화 하지 않았음에도 무사히 테스트 코드가 통과한 것을 확인할 수 있습니다.

이렇게 또 테스트 코드를 작성할때 한가지 Tip 을 배울 수 있었던 경험이었습니다.

출처 :
(https://stackoverflow.com/questions/449346/mysql-auto-increment-does-not-rollback)

(https://github.com/HomoEfficio/dev-tips/blob/master/Spring%20Data%20JPA%20%ED%85%8C%EC%8A%A4%ED%8A%B8%20%EC%8B%9C%20auto-increment%20%EB%AC%B8%EC%A0%9C.md)

(https://kth990303.tistory.com/371)