Spring Data JPA 3부터 바뀐 SEQUENCE(시퀀스) 기본키 생성 전략

마이그레이션을 진행합니다... 안되잖아?

Spring Boot 3이 공식적으로 배포되기 시작하면서, 이 참에 2.7.X 버전으로 개발중이던 프로젝트를 3.0.0으로 업그레이드 했다. 마이그레이션을 진행 하면서, 하나하나 발생한 문제를 손수 뜯어 고치고 프로젝트를 실행 했더니 이게웬걸! 뜬금없이 JPA 쪽에서 문제가 발생했다. 알고보니 기존의 Spring Data JPA 2에서 Hibernate 5를 사용하다 Spring Data JPA 3부터 Hibernate 6로 바뀌면서 생긴 문제였다.


Hibernate 6에서 변경 된 시퀀스 기본키 생성 전략

나 같은 경우에는 PostgreSQL 데이터베이스를 사용하면서, 기본키 생성 전략으로 GenerationType.SEQUECE를 사용하고 있었다. 기존에 Spring Data JPA 2에서 사용되던 Hibernate 5에서는 시퀀스를 이용한 기본키 생성 전략을 사용할 경우, 해당 데이터베이스에  hibernate_sequence라는 이름을 가진 시퀀스를 자동으로 생성한다. 이후 어떤 테이블이든 하나의 row가 추가될 때마다, 해당 row는 현재의 hibernate_sequence값을 조회한 뒤, 1을 증가시킨 값을 기본키로 부여한다. 즉, hibernate_sequence라는 시퀀스 하나를 모든 테이블이 공유 하면서 기본키를 부여 받는다. 하나의 시퀀스 만을 쓰기 때문에 Spring Data JPA 2에서 시퀀스를 이용한 기본키 생성 전략을 사용하면, 서로 다른 테이블의 id 컬럼을 모두 모아도 절대 중복된 id 값이 존재할 수 없다.

Spring Data JPA 3로 오면서 변경된 Hibernate 6에서는  테이블명_id_seq라는 이름으로, 각각의 테이블에서 사용할 수 있는 구분된 여러개의 시퀀스를 생성한다. 시퀀스를 공유하지 않고, 독립된 시퀀스를 각각의 테이블이 값을 1씩 증가시켜 사용한다. 이 때문에 얼핏 보기에는 GenerationType.IDENTITY를 사용하는 것처럼 보이기도 한다. 하지만 내부적으로는 next_val(테이블명_id_seq)를 이용해 데이터를 저장하지 않고도 식별자를 부여할 수 있으므로, 시퀀스 방식의 장점은 여전히 유효하다.

Spring Data JPA 2를 쓸 때
Spring Data JPA 3를 쓸 때

정리하며

이번에 Spring Boot를 마이그레이션 하면서 생겼던 JPA 문제를 고치는 김에 블로그 글로 남겨보았다. 만약 Spring Data JPA를 마이그레이션 하면서 시퀀스를 유지하고 싶다면 @SequenceGenerator어노테이션을 사용해 모든 id 시퀀스 명을 hibernate_sequence로 통일해 버리는 것을 고려해 보는게 좋을 것 같다.