일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- mysql equal null
- getDateCellValue
- @EntityListeners
- sendFractionalSeconds
- spring boot
- MYSQL
- 운동해서 광명찾자
- fractional seconds
- pooled-lo
- apatch poi
- mysql =
- load order
- mysql not equal null
- yml
- 1*1000
- Protecle
- AuditingEntityListener
- EmbeddedId
- getEntityGraph
- +9:00
- https
- RootGraph
- 티스토리챌린지
- deserializer
- MSSQL
- 오블완
- NamedEntityGraph
- @CreateDate
- 버전 문자열 비교
- createEntityGraph
- Today
- Total
Hello
JPA 기본키 생성 전략 본문
GenerationType.enum
JPA는 기본키 생성 전략의 타입을 정의한 enum을 제공합니다.
AUTO(default) | JPA 제공자가 DB에 대해 적절한 전략을 선택 |
IDENTITY | 데이터베이스 auto-increment 의존 JPA는 insert를 수행한 후 또는 트랜잭션 커밋 시 기본 키 값을 할당 MySQL, SQL Server, PostgreSQL, DB2, Derby, Sybase 지원 |
SEQUENCE | 데이터베이스 SEQUENCE 를 사용해 기본키 생성 트랜잭션 커밋 되고 EntityManager.persist() 호출 후에 기본키를 생성 Oracle, PostgreSQL, DB2 지원 |
TABLE | 키 생성 관리 테이블을 만들어서 SEQUENCE처럼 사용 EntityManager.persist() 호출 후 트랜잭션 커밋되기 전에 기본키를 생성 (= 권장하지 않음 이유는 아래 설명,) |
2022년에 출시된 3.1.0버전 부터 JPA는 @GeneratedValue에 사용할 수 있는 새로운 GenerationType.UUID를 제공합니다.
UUID | 엔터티의 UUID를 자동으로 생성하도록 지시 |
기술스택
spring-boot-2.x
hibernate 5.x
MySql 5.x
MySQL을 사용할 때 항상 GenerationType.IDENTITY를 명시적으로 선언해서 사용해 왔습니다. 테스트를 위해 AUTO로 실행해보았는데 JPA가 기본키 생성 전략을 잘 선택해줄 것이라고 기대했으나 hibernate_sequence 테이블이 존재하지 않는다는 에러가 발생했습니다.
stackoverflow에 나와 똑같은 이슈가 있는 사람이 있었고 해당 글의 답변을 보니 AUTO 모드 시 SEQUENCE 모드로 동작한다는 내용이 있었습니다.
왜 sequence 라는 단어가 들어간 것인지??
왜 hibernate_sequence 라는 테이블이 존재하지 않는다는 에러가 발생했는지??
왜 기대와 다르게 동작하는 것인지??
왜 이런 의문이 들었었고 이해한 내용을 정리해보려고 합니다.
GenerationType에 대해 알아보기 전에 먼저 보아야할 내용이 있습니다.
hibernate는 IdGeneratorStrategyInterpreter 인터페이스가 식별자 생성기 정보를 해석하기 위한 전략을 선택하도록 합니다. 아래 두 구현체를 제공해 버전에 따라 맞는 Interpreter를 선택 해야합니다.
determineGeneratorName 메소드가 GenerationType을 기반으로 사용해야하는 기본키 generator명을 결정 할 수 있도록 합니다. SpringBoot 버전에 따라 GenerationType.AUTO 일 때 결정되는 ID Generator가 다릅니다.
5.0 이전 : LegacyFallbackInterpreter 기본 전략. 실제 식별자 생성기를 해결하기 위해 Dialog#getNativeIdentifierGeneratorStrategy를 사용하는 네이티브 생성기 전략에 AUTO를 매핑합니다 (identity or sequence)
5.0 이후 : FallbackInterpreter 기본 전략. 기본 데이터베이스가 시퀀스를 지원하는 경우 SEQUENCE 생성기가 사용됩니다. 그렇지 않으면 TABLE 생성기가 대신 사용됩니다.
MetadataBuildingOptionsImpl 코드를 보면, idGeneratorTypeInterpreter 필드 선언과 동시에 초기화 합니다.
위 에서 값 초기화를 위해 호출된 생성자 클래스를 보면 fallbackInterpreter 필드를 FallbackInterpreter.INSTANCE 로 초기화 한것을 알 수 있습니다.
다른 설정을 하지 않는다면 hibernate는 FallbackInterpreter를 사용하게 되어 있습니다.
useNewIdentifierGenerators 기본값은 true입니다.
- Springboot 1.5.x : hibernate.id.new_generator_mappings 속성값이 false
- Springboot 2.x.x: hibernate.id.new_generator_mappings 속성값이 true
위 내용을 통해 기본 설정은 FallbackInterpreter을 선택하는 것을 알 수 있습니다. 그럼, GenerationType이 어떻게 선택되는지 한번 알아보겠습니다.
GenerationType.AUTO인데 SEQUENCE로??
디버깅을 타고타고 올라가서 GeneratedValue 어노테이션을 통해 generatorType을 찾는 코드를 발견했습니다.
AnnotationBinder.processId 일부
1. 첫번째 밑줄친 부분을 보면 GenerationValue 어노테이션을 넘겨 GenerationType 을 찾는다.Id 필드에 GenerationValue 어노테이션이 없다면 "assigned"를 갖는다.
1-1. 우리는 위 과정을 통해 FallbackInterpreter.determineGeneratorName이 호출 된 다는 것을 알 수 있다.
1-2. FallbackInterpreter.determineGeneratorName
명시적으로 generationType을 선언한 경우 각각의 타입을 리턴합니다.
default 영역을 살펴보면, {
//AUTO 주석을 보아 GenerationType.AUTO 일 때 default 영역이 실행되는 것을 짐작할 수 있습니다.
1. "increment".equalsIgnoreCase 조건 통과 시 IncrementGenerator 사용 ex)@GeneratedValue(generator="increment")
2. @Id가 선언된 필드가 UUID 일 때 UUIDGenerator 사용
3. 위 조건에 해당되지 않는다면 SequenceStyleGenerator 사용
}
@GeneratedValue(생략) 할 경우 SequenceStyleGenerator 전략을 선택하게됩니다.
generatorType는 SequenceStyleGenerator 이 된다.
strategy가 native 인 경우 사용하는 Dialect에 의해 Generator가 결정됩니다.
- 5.0이후 버전에서는 FallbackInterpreter이 사용되어 사용자가 명시하지 않는 이상 native가 될일이 없으나, LegacyFallbackInterpreter를 사용할 때, DB별 지원하는 전략을 선택합니다.
Dialect에서 Sequence기능 지원에 따라 실제 사용하는 DatabaseStructure( Table or Sequence )가 결정됩니다. Sequence기능을 지원하는 경우 SequenceStructure를 사용, 지원하지 않는 경우 TableStructure를 사용합니다.
결론 : 생략하는 것보다 명시적으로 어떤 기본키 생성 전략을 사용할 것인지 작성을 해서 다른사람이 코드를 볼 때도 어떤 방법으로 기본키가 할당되는지 알게 하도록 하는 것이 더 나은거 같단 생각이 들었다.
참고 :
https://www.baeldung.com/jpa-strategies-when-set-primary-key
https://www.baeldung.com/java-hibernate-uuid-primary-key
https://javaee.github.io/javaee-spec/javadocs/javax/persistence/GenerationType.html
'java' 카테고리의 다른 글
Java MultipartFile to String (0) | 2023.10.25 |
---|---|
[JPA] 일대일 조인 테이블 @EmbeddedId 사용 (0) | 2023.10.12 |
Apache poi excel 읽기 빈 값(null), 숫자를 문자로 읽기 (0) | 2023.04.06 |
Daylight Saving Time(DST) in JAVA (0) | 2023.04.04 |
Apache poi getDateCellValue() 엑셀과 다른 경우 (0) | 2023.02.07 |