티스토리 뷰
🎯 JPA의 ID 생성 전략
JPA는 직접 할당과 자동 할당을 통해 ID를 생성한다.
먼저, 직접 할당 방식은 @Id 어노테이션을 사용한다. 이 때 다른 어노테이션은 함께 사용하지 않고 기본키를 할당한다.
데이터베이스가 아니라 애플리케이션에서 기본 키를 직접 할당한다.
@Id
@Column(name = "ID")
private String id;
기본 키 직접 할당 전략은 em.persist()로 엔티티를저장하기 전에 기본 키를 직접 할당한다.
Book book = new Book();
book.setId("id1"); // 기본 키 직접 할당
em.persist();
그럼 기본키를 직접 할당하지 않고 데이터베이스에서 생성하주는 값을 사용하려면 어떻게 매핑해야 할까?
데이터베이스마다 기본 키를 생성하는 방식이 다르기 때문에 해당 문제를 해결하기 쉽지 않다.
JPA는 데이터베이스 기본 키 전략을 제공한다.
자동 할당
JPA에서 제공하는 데이터베이스 기본 키 생성 전략은 IDENTITY, SEQUENCE, TABLE, AUTO 전략이 있다.
기본 키 자동 할당은 @Id와 @GeneratedValue 어노테이션을 함께 사용한다.
하나씩 살펴보자
1️⃣ IDENTITY 전략
IDENTITY 전략은 기본 키 생성을 데이터베이스에 위임하는 전략이다.
주로 MySQL, PostgreSQL. SQL Server, DB2에서 사용하는 전략이다.
MySQL에서는 AUTO_INCREMENT 기능을 사용해서 기본 키 생성을 MySQL에게 넘긴다.
CREATE TABLE BOOK (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY;
TITLE VARCHAR(255)
);
이런 식으로 작성하면 ID 값을 직접 작성해주지 않아도 값이 저장될 때 자동으로 순서대로 ID값을 작성해준다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
이렇게 속성 값을 GenerationType.IDENTITY로 지정해주면 된다.
그러면 JPA는 기본 키 값을 얻어오기 위해서 데이터베이스를 추가로 조회한다.
IDENTITY 전략에서 중요한 점은 데이터베이스에 값을 저장하고 나서야 기본 키 값을 구할 수 있다는 것이다.
즉, 엔티티에 식별자 값을 할당하기 위해서 JPA가 데이터베이스를 추가로 조회해야 한다는 의미이다.
엔티티가 영속 상태가 되려면 식별자는 필수이다.
그런데 방금 설명했듯 IDENTITY 전략에서는 데이터베이스에 엔티티가 저장되어야 식별자를 구할 수 있어서 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다.
따라서 IDENTITY 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.
2️⃣ SEQUENCE 전략
SEQUENCE 전략은 유일한 값을 순서대로 생성하는 시퀀스를 사용해서 기본 키를 생성하는 전략이다.
데이터베이스 시퀀스란 유일한 값을 자동으로 생성하는 객체이다.
오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.
CREATE TABLE BOOK (
ID BIGINT NOT NULL PRIMARY KEY,
TITLE VARCHAR(255)
)
// 시퀀스 생성
CREATE SEQUENCE BOOK_SEQ START WITH 1 INCREMENT BY 1;
이렇게 시퀀스를 직접 생성한 후 엔티티와 매핑해야 한다.
@Entity
@SequenceGenerator(
name = "BOOK_SEQ_GENERATOR",
sequenceName = "BOOK_SEQ", // 매핑할 데이터베이스 시퀀스 이름
initialValue = 1,
allocationSize = 1
)
public class BOOK {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "BOOK_SEQ_GENERATOR")
private Long id;
}
@SequenceGenerator를 사용해서 시퀀스 생성기를 등록하면 JPA는 이 시퀀스 생성기를 실제 데이터베이스의 시퀀스와 매핑한다.
그리고 속성 값을 GenerationType.SEQUENCE로 지정해주면 된다.
💡 IDENTITY 전략과 SEQUENCE 전략의 차이
얼핏보면 비슷해 보이지만 차이가 존재한다.
SEQUENCE 전략은 em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한다.
그리고 조회한 식별자를 엔티티에 할당한 후 엔티티를 영속성 컨텍스트에 저장한다.
이후 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 데이터베이스에 저장한다.
IDENTITY 전략은 엔티티를 데이터베이스에 저장한 후 식별자를 조회해서 엔티티에 할당했다.
3️⃣ TABLE 전략
TABLE 전략은 키 생성 전용 테이블을 만들어 그곳에 이름과 값으로 사용할 칼럼을 만들어 시퀀스를 흉내내는 전략이다.
테이블을 사용하기 때문에 모든 데이터베이스에 적용할 수 있다.
CREATE TABLE MY_SEQUENCES (
SEQUENCE_NAME VARCHAR(255) NOT NULL,
NEXT_VAL BIGINT
PRIMARY KEY (SEQUENCE_NAME)
)
위와 같이 직접 MY_SEQUENCES라는 시퀀스 역할을 하는 테이블을 만들어서 사용한다.
@Entity
@TableGenerator(
name = "BOOK_SEQ_GENERATOR",
table = "MY_SEQUENCE",
pkColumnValue = "BOOK_SEQ",
initialValue = 1,
allocationSize = 50
)
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "BOOK_SEQ_GENERATOR")
private Long id;
}
@TableGenerator 를 사용해서 테이블 키 생성기를 등록한다.
그리고 테이블 키 생성기(BOOK_SEQ_GENERATOR)와 위에서 생성한 MY_SEQUENCES 테이블을 키 생성용 테이블로 매핑했다.
그리고 속성 값을 GenerationType.TABLE로 지정해주면 된다.
TABLE 전략은 따로 시퀀스 역할을 하는 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작 방식은 같다.
하지만 TABLE 전략은 값을 조회하면서 SELECT 쿼리를 사용하고 + UPDATE 쿼리를 통해 다음 값으로 증가시키므로 SEQUENCE 전략보다 데이터베이스와 한 번 더 조회하는 단점이 있다. 하지만 데이터베이스 종류를 타지 않기 때문에 그 점은 장점으로 볼 수 있다.
4️⃣ AUTO 전략
AUTO 전략은 데이터베이스 방언에 따라 IDENTITY, SEQUECNE, TABLE 전략 중 하나를 자동으로 선택하는 전략이다.
데이터베이스 종류에 따라 기본 키 자동 생성 전략이 가능한 방언도 있고 그렇지 않은 방언도 있었지만 AUTO 전략은 데이터베이스 방언에 따라 전략 중 하나를 자동으로 선택한다.
그래서 데이터베이스를 변경해도 코드를 수정할 필요가 없다는 장점을 가지고 있다.(개발 초기 단계에 특히 편하다.)
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
}
이렇게 속성 값을 GenerationType.AUTO로 지정해주면 된다.
기본 키 매핑 전략 정리
영속성 컨텍스트는 엔티티를 식별자 값으로 구분하므로 엔티티를 영속 상태로 만드려면 식별자 값이 반드시 있어야 한다.
- 직접 할당 : em.persist()를 호출하기 전에 애플리케이션에서 직접 식별자 값을 할당한다.
- IDENTITY : 데이터베이스에 엔티티를 저장해서 식별자 값을 획득한 후에 영속성 컨텍스트에 저장한다. 데이터베이스에 엔티티 저장이 선행되어야 한다.
- SEQUENCE : 데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다. 그 후 엔티티를 데이터베이스에 저장한다.
- TABLE : 데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
이렇게 자동 생성 전략을 사용해서 식별자를 선택해도 되고, 자연 키(NATURAL KEY)를 기본 키로 선택할 수도 있다.(주민번호, 이메일, 전화번호 등)
어쨌든 기본 키는 NULL이 아니고 + 유일해야 하고 + 변하지 않아야 한다.
참고 자료
도서 : 자바 ORM 표준 JPA 프로그래밍(김영한 지음)
'springboot' 카테고리의 다른 글
[JPA] N + 1 문제 (2) | 2024.11.20 |
---|---|
[JPA] ddl-auto 옵션 (1) | 2024.11.18 |
[SETTING] intellij에서 JAVA JDK 버전 바꾸기 (0) | 2023.11.30 |
[용어] profile (0) | 2023.10.28 |
[JPA] @NotNull vs nullable = false (0) | 2023.08.13 |
- Total
- Today
- Yesterday
- null
- @NoArgsConstructor
- JPA
- @Spring
- Java
- ddl-auto
- 유효성 검사
- Optional
- uncheckedException
- @ConfigurationProperties
- Spring
- springboot
- 동등성
- @Value
- upperBound
- Thymeleaf
- id생성전략
- 오블완
- lowerBound
- StreamAPI
- 일급컬렉션
- 생성자
- 백준
- 이진탐색
- 메인메소드
- checkedException
- 티스토리챌린지
- N+1문제
- 자바
- NPE
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |