[JPA] PK Mapping
PK 매핑
@Id
를 통해서 기본키를 매핑한다.
별도의 추가 어노테이션이 없다면 값을 직접 할당해야한다.
@GeneratedValue
를 통해서 값을 자동으로 할당해줄 수 있다.
이 어노테이션에서 속성 값으로 strategy
를 설정해줄 수 있다.
IDENTITY 전략
GenerationType.IDENTITY
의 경우 DB에 생성을 위임한다.
DB INSERT 시점에서 값을 설정한다. 즉, DB에 트랜잭션이 반영된 후에 ID 값을 알 수 있다.
하지만 영속성 컨텍스트에서 이를 관리하기 위해서는 PK 값이 존재해야 한다.
따라서, commit
시점이 아닌 persist
시점에 쿼리를 전달한다.
JDBC 내부적으로 INSERT 시점에 반환 값을 확인할 수 있어 SELECT 쿼리가 발생하지는 않는다.
CREATE TABLE `table` (
`id` bigint generated by default as identity,
`name` varchar(255) NOT NULL,
PRIMARY KEY (id)
)
INSERT INTO
`table`(id, name)
VALUES
(null, ?); // -> id 값이 JPA 에서 NULL로 입력.
Sequence 전략
GenerationType.SEQUENCE
의 경우 DB에 생성을 위임한다.
ORACLE의 SEQUENCE
와 같은 형태에 주로 적용된다.
/* HIBERNATE_SEQUENCE 객체를 생성해서 1부터 값을 증가시킴 */
CALL NEXT VALUE FOR HIBERNATE_SEQUENCE
INSERT INTO
table(id, name)
VALUES
(?, ?);
만일 테이블마다 다른 시퀀스를 쓰고싶다면?
시퀀스는 DB 시퀀스 객체에서 관리하기에 persist
시점에 DB에 접근해서 시퀀스 값을 가져온다.
@SequenceGenerator
를 통해서 테이블마다 시퀀스를 정의하면 된다.
/* 시퀀스 제네레이터 생성 */
@SequenceGenerator(name = "member_seq_generator", // 제네레이터 명
sequenceName = "member_seq")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "member_seq_generator") //시퀀스 제네레이터 지정
private Long id;
...
}
Table 전략
테이블 매핑 전략을 사용하고 싶다면?
@TableGenerator
를 통해서 키 생성 전용 테이블을 생성하고 지정하면 된다.
단, 성능 상의 단점이 있다.
/* 제네레이터 생성 */
@TableGenerator(name = "member_seq_generator", // 제네레이터 명
table = "my_sequences", //테이블 명
pkColumnValue = "member_seq") //pk 명
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "member_seq_generator") //제네레이터 지정
private Long id;
...
}
매핑 전략의 단점과 성능 개선
시퀀스, 테이블 전략 모두 DB 접근을 통해야만 pk를 확인할 수 있다.
이에 대한 성능 하락을 개선할 수 있는 방법이 있다.
initialValue
와 allocationSize
속성을 이용한다.
allocationSize
는 기본 값이 50으로 이 사이즈 만큼 DB에 미리 할당한다.
allocationSize
단위 만큼 메모리 상에서 관리하므로 그만큼 네트워크 부하가 줄게 된다.
PK 제약 조건
PK 제약 조건은 NOT NULL
, 변하지 않아야 하는 특성을 가진다.
이를 만족시키는 키를 찾기가 어렵다.
따라서, 대체키와 키 생성 전략을를 추가적으로 함께 사용하는 것이 좋다.