[JPA] H2의 @GeneratedValue 문제
개요
프로젝트를 진행하던 도중 아직 User 관련된 기능들이 완성되지 않아서 DB에 초기값을 insert하기 위해 웹 서버를 실행하는 시점에 값을 insert 하기로 결정하였다.
필요한 파일과 설정 준비
우선 resources 밑에 값 세팅을 위한 insert를 적어둘 data.sql을 생성하였다.
data.sql
insert into user (created_date,last_modified_date, email, password, name, provider, user_image_url, entrance_year, graduation_year)
values (NOW(), NOW(), 'admin@email.com', '1234', '홍길동', 'KAKAO', '/img', now(), now());
PK인 user_id 값은 자동으로 할당되는 것을 쓰기위해 비워두고 insert를 진행한다.
그 다음 스프링이 이러한 sql 파일을 인식하기 위하여 application.yml에 설정을 추가하였다.
개발 중에 있었기 때문에 h2 database를 사용하고 있었고 DB 연결을 위한 세팅이 적혀있었다. 추가적으로 아까 만들어둔 data.sql 인식을 위하여 data와 initialization-mode를 설정하였다.
기본키 할당을 위해서는 @GeneratedValue의 기본 값인 AUTO를 그대로 사용하였다.
이제 모든 준비가 끝나고 웹 서버를 실행하였다.
하지만 user_id 값이 PK인데 할당이 되지 않아 관련된 예외를 던지고 있다. 결국 id 값이 자동으로 할당되지 않는다는 것을 알 수 있다.
로그를 확인해 보아도 자동으로 id 값을 설정 관련한 제약 조건을 찾아볼 수 없었다. 단순히 PK를 설정할 뿐이었다.
관련한 자료를 찾기 위하여 기본키 생성 전략에 대하여 찾아보았다.
기본 키 매핑
@GeneratedValue(strategy = GenerationType.IDENTITY)
- 기본 키 생성을 데이터베이스에 위임한다. 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다. 보통 id 값은 비워두고 자동으로 데이터베이스에서 자동으로 값을 입력한다. 그렇기 때문에 데이터베이스에 값을 저장하고 나서야 비로소 기본 키 값을 구할 수 잇다.
이 전략을 사용하면 JPA는 기본 키 값을 얻어오기 위해 데이터베이스를 추가로 조회하게 된다. 즉 em.persist()를 호출해서 엔티티를 저장한 직후 할당된 식별자 값을 조회하여 영속성 컨텍스트에 값을 채워 넣는다.
@GeneratedValue(strategy = GenerationType.SEQUENCE)
- 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다. SEQUENCE 전략은 이 시퀀스를 사용하여 기본키를 생성한다. 주로 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.
@GeneratedValue(strategy = GenerationType.TABLE)
- 키 생성 전용 테이블을 생성하여 데이터베이스 시퀀스 처럼 사용한다. 이 전략은 테이블을 사용하기 때문에 모든 데이터베이스에 적용이 가능하다.
@GeneratedValue(strategy = GenerationType.AUTO)
- 생성전략의 default 값인 AUTO이다. 데이터베이스의 종류는 다양하고 기본키를 만드는 방법도 다양하다. JPA는 이러한 데이터베이스에 모두 대응해야 한다. 그렇기 때문에 선택한 데이터베이스에 따라 위 3가지 전략 중 자동으로 하나를 선택하여 적용한다.
우리 프로젝트는 개발 중에 H2를 사용하기로 하였고 기본전략으로 SEQUENCE를 선택하였다고 생각한다. 그렇기 때문에 데이터베이스에 insert하는 시점에 식별자를 채워야 하기 때문에 지속적으로 예외를 던진것으로 판단되었다.
개발이 완료되면 배포 시 mySQL을 사용할 예정이기 때문에 코드 수정을 최소화 하기 위하여 IDNETITY를 명시적으로 작성하였다. 변경하여 table ddl 문과 insert가 잘 되었는지 확인해보았다.
이제 기본키 생성은 전적으로 데이터베이스가 위임할 것이다.
테이블 생성을 위한 ddl을 확인해보면 이전에 없던 generated by default as identity를 확인할 수 있다. H2 database가 기본키 할당을 자동으로 하기 위해 추가한 것으로 예상된다.
H2 console을 확인하여 user를 조회해보면 자동으로 id 값이 할당된 user 값이 정상적으로 insert 된 것을 확인할 수 있었다.
이렇게 기본키 생성 전략으로 인한 로직을 간접적으로 확인할 수 있는 기회가 되었다. 앞으로는 데이터베이스의 종류에따라서 어떠한 생성전략을 가져가야 할지에 대한 고민을 해야 겠다는 생각이 들었다.