기본키(primary key) 매핑하는 방법은 총 2가지로 직접 할당과 자동 생성이 있다.
- 직접 할당 : @Id 어노테이션만 사용하여 Id값을 직접할당
- 자동 생성 : @Id와 @GeneratiedValue를 사용하여 원하는 키 생성 전략을 선택
자동 생성의 키 생성 전략은 다음과 같이 4가지로 분류 된다.
키 생성 전략
- IDENTITY : 데이터베이스에 위임 (MYSQL)
- SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용 (ORACLE)
- TABLE : 키 생성용 테이블 사용 (모든 DB에서 사용)
- AUTO : dialect(방언) 설정에 따라 자동 지정 (기본값)
이 각 키 생성 전략에 대해 자세히 알아보자.
IDENTITY 전략
기본 키 생성을 데이터베이스에 위임하는 전략
(주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용)
이 전략을 사용하면 DB가 기본 키를 알아서 생성 해주므로 엔티티 값을 넣어줄 때 id 값을 빼고 값을 세팅해줘도 된다.
(엔티티의 생성자가 id 필드를 매개변수로 받지 않아도 된다.)
SEQUENCE 전략
데이터베이스 시퀀스를 사용하여 기본키를 생성하는 전략.
시퀀스란 일련번호를 생성하는 특수한 객체로, 일련번호를 하나하나씩 증가시키며 생성한다.
이렇게 생성된 일련번호를 기본키로 사용하는 것을 SEQUENCE 전략이라고 한다.
(주로 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용)
속성 값
속성 | 설명 | 기본값 |
name | 식별자 생성기 이름 | 필수 |
sequenceName | 데이터베이스에 등록되어 있는 시퀀스 이름 | hibernate_sequence |
initialValue | DDL 생성 시에만 사용. 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다 |
1 |
allocationSize | 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용) | 50 |
catalog, schema | 데이터베이스 catalog, schema 이름 |
allocationSize의 값은 기본값이 50이다.
따라서 기본값을 사용하면 sequence 호출마다 50씩 증가하게 된다.
데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값 을 반드시 1로 설정해야 한다
allocationSize 기본값이 50인 이유?
JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 allocationSize를 사용한다.
allocationSize로 설정한 값 만큼 한번에 시퀀스 값을 증가시키고 나서, 그만큼 메모리에 시퀀스 값을 할당한다.
만약 allocationSize가 50이라면, 시퀀스를 한 번 조회 시 50을 증가시킨 다음에, 1~50 까지는 메모리에서 식별자를 할당하고
51이 되면 시퀀스 값을 100으로 증가시킨 다음 51~100까지 메모리에서 식별자를 할당한다.
이 방법은 시퀀스 값을 선점하므로 여러 JVM에서 동시에 동작해도 기본 키 값이 충돌하지 않는다는 장점이 있다.
하지만 데이터베이스에 직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가하므로, 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값 을 반드시 1로 설정해야 한다
TABLE 전략
키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략
모든 데이터베이스에 적용 가능하지만 성능이 떨어진다.
@Entity
@NoArgsConstructor
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = "MEMBER_SEQ", allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "MEMBER_SEQ_GENERATOR")
private Long id;
@Column
private String name;
public Member(String name) {
this.name = name;
}
}
위 엔티티 클래스를 name을 "AAAA"로 (Member("AAAA")) DB에 저장해보았다.
총 2개의 테이블이 생성된 것을 볼 수 있다.
MY_SEQUENCES 테이블을 살펴보면 다음과 같다.
Member 테이블은 위 MY_SEQUENCES 테이블의 Id값을 참조하고 있다.
잘 사용하지 않는 전략이므로 자세한 설명은 생략한다.
AUTO 전략
dialect(방언) 설정 값에 따라 위 셋의 전략중 하나를 자동으로 선택한다.
(ex: Oracle이면 SEQUENC, MySQL이면 IDENTITY를 사용)
@GeneratedValue의 기본값은 AUTO이기에 AUTO 전략을 사용하면 속성값을 지정하지 않아도 된다.
권장하는 기본키 선택 전략
기본 키 종류 | 설명 | 예시 |
자연키 | 비즈니스에 의미가 있는 키 | 주민등록 번호, 이메일 |
대리키 (대체키) | 비즈니스와 관계 없는 키 | AUTO_INCREMENT, 임의로 만들어진 키 |
기본 키는 다음과 같은 제약조건을 갖고 있다.
기본 키 제약 조건
- null 이 아니다.
- 유일해야 한다.
- 변하면 안된다.
그런데, 미래까지 기본키 제약 조건을 만족하는 자연키는 찾기 어렵다.
예를 들어 주민등록 번호(자연키)를 기본 키로 사용한다고 가정해보자.
미래에 갑자기 정책이 변경되어 데이터베이스에 주민번호를 저장하지 못하게 막는다면 모든 키를 변경해야한다.
그러므로 대리키(대체키)를 사용하는 것을 권장한다.
// (Long 타입 + 대체키 + 키 생성전략)
@Id
@GenerateValue
private Long id;
결론
어떤 전략을 선택해야하는지 고민이라면
MySQL은 IDENTITY 전략
ORACLE은 SEQUENCE 전략
데이터베이스에 맞춰 선택하자.
'◼ JAVA > JPA' 카테고리의 다른 글
[JPA] 연관관계 매핑 총 정리 (0) | 2023.06.06 |
---|---|
[JPA] 연관관계 매핑 주인에 대해서 (mappedBy) (0) | 2023.06.06 |
[JPA] 엔티티 매핑 어노테이션과 속성 값 정리 (0) | 2023.06.05 |
[JPA] 데이터베이스 초기화 전략 (ddl auto 옵션) (0) | 2023.06.04 |
[JPA] dialect란? (0) | 2023.06.04 |