아래 내용은 김영한님의 '자바 ORM 표준 JPA 프로그래밍' 책의 내용을 요약하였습니다.
chapter 4 2편이고
1편은 다음 링크에 있습니다~
https://dkan9634.tistory.com/159
[JPA] Chapter 4 엔티티 매핑 1
아래 내용은 김영한님의 '자바 ORM 표준 JPA 프로그래밍' 책의 내용을 요약하였습니다. Chapter 4. 엔티티 매핑 JPA를 사용하는 데 가장 중요한 일 엔티티와 테이블을 정확히 매핑하는 것 따라서 매핑
dkan9634.tistory.com
4.6 기본 키 매핑
기본 키를 애플리케이션에 직접 할당하는 대신에 데이터베이스가 생성해주는 값을 사용하려면 어떻게 매핑해야 할까?
데이터베이스마다 기본 키를 생성하는 방식이 서로 달라 방법이 다르지만 JPA는 이렇게 해결한다
- 직접 할당: 기본 키를 애플리케이션에서 직접 할당한다.
- 자동 생성: 대리 키 사용 방식
- IDENTITY: 기본 키 생성을 데이터베이스에 위임한다.
- SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키를 할당한다.
- TABLE: 키 생성 테이블을 사용한다.
=> 자동 생성 전략이 다양한 이유는 데이터베이스 벤더마다 지원하는 방식이 다르기 때문
ex) 시퀀스 - 오라클DB ⭕, MySQL ❌(AUTO_INCREMENT)
그래서 SEQUENCE나 IDENTITY 전략은 사용하는 데이터베이스에 의존
TABLE 전략은 키 생성용 테이블을 하나 만들어두고 마치 시퀀스처럼 사용하는 방법(모든 DB ⭕)
기본 키를 직접 할당하려면 @Id만 사용
자동 생성 전략을 사용하려면 @Id에 @GeneratedValue를 추가하고 원하는 키 생성 전략 선택
+) 키 생성 전략을 사용하려면 persistence.xml에
hibernate.id.new_generator_mappings=true
속성을 반드시 추가해야 함
4.6.1 기본 키 직접 할당 전략
: em.persist()로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방법
Board board = new Board();
board.setId("id1") // 기본 키 직접 할당
em.persist(board);
4.6.2 IDENTITY 전략
: 기본 키 생성을 DB에 위임하는 전략
DB에 값을 저장하고 나서야 기본 키 값을 구할 수 있을 때 사용
개발자가 엔티티에 직접 식별자를 할당하면 @Id 어노테이션만 있으면 되지만 지금처럼 식별자가 생성되는 경우에는 @GeneratedValue 어노테이션을 사용하고 식별자 생성 전략을 선택해야 한다.
IDENTITY 전략을 사용하려면 @GeneratedValue의 strategy 속성 값을 GenerationType.IDENTITY로 지정
이 전략을 사용하면 JPA는 기본 키 값을 얻어오기 위해 데이터베이스를 추가로 조회
// IDENTITY 매핑 코드
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
// IDENTITY 사용 코드
private static void logic(EntityManager em) {
Board board = new Board();
em.persist(board);
System.out.println("board.id = " + board.getId());
}
// 출력 : board.id = 1
이 코드를 보면 em.persist() 를 호출해서 엔티티를 저장한 직후에 할당된 식별자 값을 출력했다.
출력된 값 1은 저장 시점에 데이터베이스가 생성한 값을 JPA가 조회한 것이다.
**주의
엔티티가 영속 상태가 되려면 식별자가 반드시 필요
그런데 IDENTITY 식별자 생성 전략은 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다. 따라서 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다. **
4.6.3 SEQUENCE 전략
DB 시퀀스는 유일한 값을 순서대로 생성하는 특별한 DB 오브젝트
이 시퀀스를 사용해서 기본 키를 생성한다.
// 시퀀스 DDL
CREATE TABLE BOARD (
ID BIGINT NOT NULL PRIMARY KEY,
DATA VARCHAR(255)
)
//시퀀스 생성
CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;
// 시퀀스 매핑 코드
@Entity
@SequenceGenerator(
name = "BOARD_SEQ_GENERATOR",
sequenceName = "BOARD_SEQ", // 매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize=1 )
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "BOARD_SEQ_GENERATOR")
private Long id;
...
}
우선 사용할 데이터베이스 시퀀스를 매핑해야 한다.
1) @SequenceGenerator를 사용해서 BOARD_SEQ_GENERATOR라는 시퀀스 생성기를 등록
2) sequenceName 속성의 이름으로 BOARD_SEQ를 지정했는데 JPA는 이 시퀀스 생성기를 실제 DB의 BOARD_SEQ 시퀀스와 매핑
3) 키 생성 전략을 Genration, SEQUENCE로 설정하고 generator = "BOARD_SEQ_GENERATOR"로 방금 등록한 시퀀스 생성기를 선택했다.
이제부터 id 식별자 값은 BOARD_SEQ_GENERATOR 시퀀스 생성기가 할당한다.
// 시퀀스 사용 코드
private static void logic(EntityManger em) {
Board board = new Board();
em.persist(board);
System.out.println("board.id = " + board.getId());
}
// 출력: board.id = 1
IDENTITY 전략과 같지만 내부 동작 방식은 다르다.
SEQUENCE 전략
- em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한다.
- 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.
- 이후 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 테이터베이스에 저장한다.
IDENTITY 전략
- 엔티티를 데이터베이스에 저장한 후에 식별자를 조회해서 엔티티의 식별자에 할당한다.
4.6.4 TABLE 전략
키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 테이터베이스 시퀀스를 흉내낸다.
테이블을 사용하므로 모든 데이터베이스에 적용 가능
이 전략을 사용하려면 키 생성 용도로 사용할 테이블을 만들어야 한다.
// TABLE 전략 키 생성 DDL
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key (sequence_name)
)
// TABLE 전략 매핑 코드
@Entity
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
sequenceName = "MY_SEQUENCES", // 매핑할 데이터베이스 시퀀스 이름
pkColumnValue = "BOARD_SEQ",
allocationSize = 1
)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "BOARD_SEQ_GENERATOR")
private Long id;
...
}
@TableGenerator로 테이블 키 생성기를 등록
BOARD_SEQ_GENERATOR라는 이름의 테이블 키 생성기를 등록하고 방금 생성한 MY_SEQUENCES 테이블을 키 생성용 테이블로 매핑했다.
이제부터 id 식별자 값은 BOARD_SEQ_GENERATOR 테이블 키 생성기가 할당한다.
//TABLE 전략 매핑 사용 코드
private static void logic(EntityManger em) {
Board board = new Board();
em.persist(board);
System.out.println("board.id = " + board.getId());
}
// 출력: board.id = 1
시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식이 같다.
4.6.5 AUTO 전략
장점은 데이터베이스를 변경해도 코드를 수정할 필요가 없다.
사용할 때 SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다.
4.6.6 기본 키 매핑 정리
영속성 컨텍스트는 엔티티를 식별자 값으로 구분하므로 엔티티를 영속 상태로 만들려면 식별자 값이 반드시 있어야 한다.
em.persist()를 호출한 직후에 발생하는 일을 식별자 할당 전략별로 정리하면 다음과 같다.
- 직접 할당: em.persist()를 호출하기 전에 애플리케이션에서 직접 식별자 값을 할당해야 한다.
- SEQUENCE: DB 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
- TABLE: DB 시퀀스 생성용 테이블에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
- IDENTITY: DB에 엔티티를 저장해서 식별자 값을 획득한 후 영속성 컨텍스트에 저장한다.
<권장하는 식별자 선택 전략> (모두 만족해야 함)
1. null X
2. 유일
3. 변해선 X
테이블의 기본키를 선택하는 전략 2가지
1. 자연 키(natural key) - 비즈니스에 의미가 있는 키 ex) 주민등록번호, 이메일, 전화번호
2. 대리 키(surrogate key) - 비즈니스와 관련 없는 임의로 만들어진 키, 대체 키로도 불린다.
자연 키보다는 대리 키를 권장한다
비즈니스 환경은 언젠가 변한다
JPA는 모든 엔티티에 일관된 방식으로 대리 키 사용 권장
Reference)
자바 ORM 표준 JPA 프로그래밍 - 김영한 지음
'Server' 카테고리의 다른 글
[AWS] EC2 인스턴스 제대로 생성하기 (0) | 2023.08.08 |
---|---|
[JPA] Chapter 5. 연관관계 매핑 기초 (0) | 2023.05.25 |
[JPA] Chapter 4 엔티티 매핑 1 (0) | 2023.05.11 |
[JPA] Chapter 3 영속성 관리 (0) | 2023.05.05 |
[JPA] Chapter 2 JPA 시작 (0) | 2023.04.26 |