Blog

[Spring]33 Entity 클래스에서 PK의 GenerationType의 종류

Author
Summary
@
Category
Study
Tags
Spring
Favorite
Memory Date
2023/09/06
Cross Reference Study
Related Media
Related Thought
Related Lessons
tag
날짜
작성자
진행상황
진행 전
태그구분
6 more properties
@Id 어노테이션?
@Id 데이타베이스의 테이블은 기본적으로 유일한 값을 가진다. 그것을 PK (Primary Key) 라고 하는데 데이타베이스는 이 유일한 키값을 기준으로 질의한 데이타를 추출해 결과셋으로 반환한다.
테이블 상에 PK가 없는 테이블도 있지만 대부분의 경우 반드시 PK가 존재한다. JPA 에서도 Entity 클래스 상에 해당 PK 를 명시적으로 표시를 해야 되는데 그것을 @Id 어노테이션을 이용해 이것이 PK 임을 지정 할 수 있다.
만약 Spring Boot 의 spring jpa.hibernate.ddtauto 속성이 create 로 되어 있고 아직 해당 테이블이 데이타베이스상에 존재하지 않는다면 EntityManager 가 DDL 을 통해 테이블을 생성하면서 PK를 같이 생성해 준다.
@GeneratedValue 어노테이션
@GeneratedValue PK 컬럼의 데이타 형식은 정해져 있지는 않으나 구분이 가능한 유일한 값을 가지고 있어야 하고 데이터 병합으로 인해 발생되는 데드락 같은 현상을 방지 하기 위해 대부분 Bigint 즉 Java 의 Long 을 주로 사용한다. 물론 String 형태의 고정된 키값을 직접 생성해서 관리하는데 대량의 요청이 유입 되더라도 중복과 deadlock 데드락이 발생 되지 않을 만큼 키값 이 빨리 생성이 되고 안전하게 관리 되어야 한다.
가장 보편적으로 사용이 되는 데이터베이스인 MySQL, ORACLE 에는 Long 타입의 키값을 생성하는 방식으로 MySQL 은 Auto increment 방식을, Oracle 은 Sequence 방식을 사용한다.
여기서 SpringBoot는 @Entity 어노테이션을 통해 JPA가 관리 할 수 있는 Entity 클래스를 지정 할 수 있으며 @Table을 통해 DB 테이블과 맵핑을 하게 된다. 클래스 내부의 각 필드 멤버들은 @Column이라는 어노테이션으로 각각 맵핑되게 된다. 그 필드 중 DB의 PK와 연결되는 필드의 경우 @Id 어노테이션을 사용하여 PK임을 지정 할 수 있고 증가 전략인 @GeneratedValue(strategy=GenerationType.<Option>)을 통해 세부 방식을 선택하게 된다. <Option>에 해당되는 부분은 아래와 같이 정리된다.
IDENTITY
기본키 생성을 DB에게 위임한다. (MySQL의 경우는 AUTO INCREMENT)
즉 특정 DB 벤더에 의존적이다. (증가 전략을 DB측에 위임하는 방식이다.)
Id가 null일 경우 해당 객체의 Id를 DB의 AUTO_INCREMENT를 가져와 할당한다.
객체를 저장할 때 벌어지는 일
JPA에서 영속성 컨텍스트에서 객체를 관리하기 위해서는 무조건 ID 속성, 즉 PK 값이 있어야 한다.
(JPA 입장에서는 Map의 key 값이 없다면 해당 객체의 값을 넣을 수 있는 방법이 없기 때문이다.)
그런데 AUTO_INCREMENT 경우 애플리케이션에서는 그 값이 얼마임을 알지 못하기에 DB에 insert문을 날려야 id 값을 알 수 있다.
이말인 즉슨
객체를 save() 메서드로 저장을 할 때 원래는 트랜잭션이 끝나는 COMMIT 시점 전에 flush가 이루어지지만,
해당 경우는 DB에서 id 값을 받아와야 하니 save() 메서드를 호출하는 시점에 insert 쿼리가 나간다. (flush가 이루어진다.)
이렇게 id 값을 할당한 객체는 영속성 컨텍스트 1차 캐시에 값을 넣게된다.
SEQUENCE
DB의 Sequence 객체를 이용해 유일한 값을 순서대로 생성한다.
즉 특정 DB 벤더에 의존적이다.
이 전략은 sequence를 사용하는 Oracle, DB2, H2 등의 DB에서 사용한다.
@SequenceGenerator(시퀀스를 생성하는 어노테이션)과 함께 사용할 수 있다.
만약 sequence 객체를 사용하지 않는 DB 벤더를 이용할 경우 Sequence를 관리할 객체(테이블)을 생성한다.
단 jpa ddl auto 설정이 되어있어야 한다.
객체를 저장할 때 벌어지는 일
IDENTITY 전략과 다른점이 존재한다.
해당 전략은 단순히 sequence 값만 시퀀스 객체에서 조회해오면 되기에, 엔티티 테이블에 해당 객체를 바로 insert 할 필요가 없다.
이말인 즉슨
객체를 save() 메서드로 저장을 할 때 id 값을 채우기 위해 select 문이 실행되고, 트랜잭션이 끝나는 COMMIT 시점에 insert 문이 실행된다.
TABLE
특정 벤더에 의존적이지 않다.
시퀀스 테이블을 만들어서 데이터베이스 시퀀스를 흉내낼 Id를 할당한다.
이 전략을 사용할 시, jpa ddl auto 설정이 되어 있지 않았다면 해당 시퀀스 테이블 생성이 선행이 되어야한다.
@TableGenerator(테이블 생성 어노테이션)과 함께 사용할 수 있다.
만약 jpa ddl auto 설정이 되어있다면 hibernate가 시퀀스 테이블을 생성한다.
AUTO
DB 벤더에 따라 자동으로 3가지 전략 중 하나를 선택한다.
DB 벤더를 변경해도 전략을 수정하지 않아도 되지만,
SEQUENCE나 TABLE 전략을 선택한다면 sequence나 키 테이블을 생성해두어야 함을 주의하자.
근데 JPA ddl-auto 기능을 사용하면 위의 예제 처럼 hibernate가 알아서 시퀀스 테이블을 생성해준다.