스프링 부트 2.0 JPA Auto-configuration의 변화

스프링 애플리케이션을 만들 때 스프링 프레임워크Spring Framework로 직접 구성하기보다는  스프링 부트Spring Boot를 사용하는 것이 더 간단하고 쉽다. 그리고 그 중심에는 스프링 부트 자동 설정Auto-configuration이 있다. 스프링 부트 자동 설정은 스프링 애플리케이션에 추가한 라이브러리(JAR)를 인식하여 관련 값을 스프링 부트 기본으로 설정해 준다. 따라서 스프링 부트를 사용하는 입장에서는 자동으로 해주는 부분 이외에 필요한 설정만 하면 되니 편하다.

최근 스프링 부트 2.0이 공개되었다. 많은 변화가 있지만 이 글에서는 변화된 JPAJava Persistence API 자동 설정에 대해 다룬다.

StackOverFlow를 보다가

StackOverFlow는 스택 익스체인지 네트워크의 대표 사이트로 컴퓨터 프로그래밍에 관련된 폭넓은 주제로 질문과 답을 하는 곳이다.[1]

StackOverFlow에서 필자는 'Has Spring-boot changed the way auto-increment of ids works through @GeneratedValue?'라는 제목의 질문을 보았는데 질문의 요지는 스프링 부트에서 JPA @GeneratedValue가 스프링 부트 1.5와 2.0이 다르게 동작하는 이유가 무엇이냐는 것이었다.

갈무리. https://stackoverflow.com/questions/49241216/has-spring-boot-changed-the-way-auto-increment-of-ids-works-through-generatedva

갈무리. https://stackoverflow.com/questions/49241216/has-spring-boot-changed-the-way-auto-increment-of-ids-works-through-generatedva

JPA GeneratedValue 어노테이션

GeneratedValue는 데이터베이스 테이블 주키Primary Key를 자동 생성하는 기능이다. 자동 생성 전략을 4개로 지정해 줄 수 있는데 지정해 주지 않으면 기본값은 'AUTO'이다.

생성 전략

설명
AUTO(default) JPA 구현체가 자동으로 생성 전략을 결정한다.
IDENTITY 기본키 생성을 데이터베이스에 위임한다. 예를 들어 MySQL의 경우 AUTO_INCREMENT를 사용하여 기본키를 생성한다.
SEQUENCE 데이터베이스의 특별한 오브젝트 시퀀스를 사용하여 기본키를 생성한다.
TABLE 데이터베이스에 키 생성 전용 테이블을 하나 만들고 이를 사용하여 기본키를 생성한다.

출처 : 자바 ORM 표준 JPA 프로그래밍 4.6 기본키 매핑

더 자세한 내용은 필자의 이전 글 '하이버네이트는 어떻게 자동 키 생성 전략을 결정하는가'에 나와 있다.

문제 확인

StackOverFlow 질문자의 코드를 MySQL로 스프링 부트 1.5와 2.0으로 테스트해 보았다. 질문자의 코드는 GeneratedValue 어노테이션에 자동 생성 전략을 지정해 주지 않았기 때문에 'AUTO'이며 이것은 곧 JPA 구현체(하이버네이트)가 자동으로 결정하라는 의미이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Airplane {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  //...
}
@Entity
public class Car {
  @Id
  @GeneratedValue
  private Long id;
  private String name;
  //...
}

하이버네이트의 스키마 자동 생성 기능[2]을 사용하여 생성된 스키마를 확인해 보았더니 결과는 아래와 같았다.

스프링 부트 1.5 스프링 부트 2.0
image2018-10-1_10-0-20 image2018-10-1_10-1-4

표. 스프링 부트 하이버네이트 로그

같은 코드임에도 불구하고 스프링 부트 1.5에서는 MySQL의 auto_increment를 사용하는데 반해 2.0에서는 hibernate_sequence 테이블을 추가로 생성하고 이를 사용하여 INSERT 시 id 값을 채우고 있다.

왜 다르게 동작하는가

우선 스프링 부트에서 사용하고 있는 하이버네이트 버전이 다르다. 1.5는 하이버네이트 5.0을 사용하고 2.0은 하이버네이트 5.2를 사용한다. 하이버네이트 버전이 달라져서 그런 것일까?

결론부터 말하자면 하이버네이트 버전하고는 상관없다. 스프링 부트 2.0에서 JPA 자동 설정 코드를 변경했다. GeneratedValue(AUTO)를 사용하는 경우 하이버네이트는 여러 가지를 고려하여 키 생성 전략을 자동으로 판단하는데[3] 스프링 부트의 하이버네이트 자동 설정이 1.5에서 2.0으로 버전이 올라가면서 변경되었고 이 영향으로 하이버네이트 키 생성 전략이 달라진 것이다.

스프링 부트 JPA Auto-configuration

앞서 필자는 스프링 부트 JPA 자동 설정 과정에서 하이버네이트 '키 생성 전략 결정에 영향을 주는 값'을 설정해 주는 코드가 2.0에서 변경되었다고 언급했다. 그 값은 바로 'hibernate.id.new_generator_mappings' 이다. 스프링 부트는 하이버네이트  'hibernate.id.new_generator_mappings' 프로퍼티 기본 값을 1.5 버전에서는  'FALSE'로 2.0 버전에서는 'TRUE'로 설정한다.

갈무리. 스프링 부트 1.5 코드 'hibernate.id.new_generator_mappings' 프로퍼티를 FALSE로 설정

갈무리. 스프링 부트 1.5 코드 'hibernate.id.new_generator_mappings' 프로퍼티를 FALSE로 설정

갈무리. 스프링 부트 2.0 코드 'hibernate.id.new_generator_mappings' 프로퍼티를 TRUE로 설정

갈무리. 스프링 부트 2.0 코드 'hibernate.id.new_generator_mappings' 프로퍼티를 TRUE로 설정

하이버네이트는 'hibernate.id.new_generator_mappings' 프로퍼티 값에 따라 자동 생성 전략을 결정한다.

그림. 하이버네이트 Interpreting AUTO

그림. 하이버네이트 Interpreting AUTO

정리

스프링 부트 1.5는 hibernate.id.new_generator_mappings 가 'FALSE'이기 때문에 하이버네이트 자동 키 생성 전략이 Native Generator가 되어 방언(MySQL5Dialect)에 따라 'auto_increment'가 된 것이며, 스프링 부트 2.0에서는 'TRUE' 이기 때문에 SequenceStyleGenerator를 사용하게 되고 MySQL이 Sequence를 지원하지 않기 때문에 Table Generator가 된 것이다.

만약 스프링 부트 2.0에서 1.5와 동일하게 사용하고자 한다면 application.properties에 아래와 같이 추가한다.

1
spring.jpa.properties.hibernate.id.new_generator_mappings = false

덧붙여

스프링 부트 1.4 릴리즈 노트에 이와 관련된 내용을 찾을 수 있다.

갈무리. 스프링 부트 1.4 릴리즈 노트

갈무리. 스프링 부트 1.4 릴리즈 노트

또한 스프링 부트 GitHub에도 역시 스프링 부트 2.0에서 이 값이 변경된 이력을 찾을 수 있다.

갈무리. https://github.com/spring-projects/spring-boot/issues/7612

갈무리. https://github.com/spring-projects/spring-boot/issues/7612

주석

[1] https://en.wikipedia.org/wiki/Stack_Overflow

[2] https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#configurations-hbmddl

스프링 부트에서는 아래와 같이 설정한다.

1
2
3
4
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.jpa.properties.hibernate.format_sql=true

[3] 상세한 내용은 '하이버네이트는 어떻게 자동 키 생성 전략을 결정하는가' 글 '하이버네이트 Interpreting AUTO'절 참조


Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.