엔티티는 반드시 기본 키를 필요로 하며 @Id로 할당한다. 이 때 기본 키를 테이블과 맵핑 시킬 때 여러가지 전략이 있다.
@Id만 사용하면 되며 기본 키(PK) 특징상 not null이기에 사용시 반드시 직접 할당 해줘야한다.
@Entity
public class Member{
@Id
private Long id;
}
public class Main{
public void run(){
Member member = new Member();
member.setId(1L);
em.persist(member);
}
}
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
IDENTITY는 기본 키 생성을 DB에 위임하는 것 이다. MySQL의 AUTO_INCREMENT를 사용할 수 있게 해준다고 생각하면 된다.
생각해보면 JPA는 em.persist(entity);로 데이터를 추가하면 영속성 컨텍스트에 먼저 저장 후 DB로 데이터를 추가하는 시점은 어쨋든 flush가 일어날 때다.
근데 IDENTITY방식은 기본 키를 DB에 위임해주기 때문에 DB에 데이터를 넣기 전까지 기본 키의 정보를 알 수 없어 영속성 컨텍스트를 사용 할 수가 없다. 때문에 IDENTITY는 지연쓰기 기능을 사용하지 못하고 바로 DB에 데이터를 넣고 조회해서 영속성 컨덱스트에 엔티티 정보를 저장하는 방식으로 동작한다.
Entity
@SequenceGenerator(
name = “MEMBER_SEQ_GENERATOR",
sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
SEQUENCE는 오라클DB의 SEQUENCE와 같이 유일한 값을 순서대로 생성하는 방식이다.
@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;
TABLE은 기본 키 전용 테이블을 생성한 뒤 해당 테이블에서 값을 가져와 기본 키로 사용하는 것을 말한다. SEQUENCE와 같은 기능을 전용 테이블을 하나 만들어 사용한다고 생각하면 편하다.
이 방법은 장단점이 확실한데, 장점은 모든 DB에서 사용이 가능하다는 점이고 단점은 성능이 떨어진다.
DB에 따라 위 종류 중 하나를 자동 선택
SEQUENCE - @SequenceGenerator, TABLE - @TableGenerator 에는 allocationSize라는 속성이 있다.
allocationSize는 기본 키 정보를 가져올 때 몇 개씩 가져올지 결정하는 것인데, 성능 튜닝에 좋다고 한다.
보통 WAS에서 테이블에 데이터를 추가할 때 기본 키 정보를 1개씩 호출 해서 정보를 받아 사용하는데, allocationSize는 뭉탱이로 많이 가져와서 메모리에 저장 후 해당 테이블에 데이터를 추가할 때 기본 키를 메모리에 저장된 데이터를 할 당한다.
예시
유저 50명을 추가 한다고 가정
- allocationSize가 1일 때(기본)
- 기본 키 채번 후 유저에게 할당
- 이걸 50번 반복.
- allocationSize가 30일 때
- 기본 키를 30개 채번 후 30명의 유저에게 할당
- 기본 키를 30개 다시 채번 후 나머지 유저 20명에게 할당