기본키를 자동으로 생성할 때에는 @Id와 @GenerratedValue 어노테이션이 함께 사용되어야 한다.
@Entity
public class PkEx() {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
JPA는 보통 영속성 컨텍스트에서 객체를 관리하다가 commit이 호출되는 시점에 쿼리문을 실행하게 된다. 하지만 IDENTITY 전략에서는 EntityManager.persist()를 하는 시점에 Insert SQL을 실행하여 데이터베이스에서 식별자를 조회해온다.
그 이유는 영속성 컨텍스트는 1차 캐시에 PK와 객체를 가지고 관리를 하는데 기본키를 데이터베이스에게 위임햇기 때문에 EntityManager.persist()호출 하더라도 데이터베이스에 값을 넣기 전까지 기본키를 모르고 있기 때문에 관리가 되지 않기 때문이다.
따라서 특별한 경우로 IDENTITY 전략에서는 EntityManager.persist()를 하는 시점에 Insert SQL을 실행하여 데이터베이스에서 식별자를 조회하여 영속성 컨텍스트 1차 캐시에 값을 넣어주기 때문에 관리가 가능해진다.
@Entity
@SequenceGenerator(
name = "USER_PK_GENERATOR",
sequenceName = "USER_PK_SEQ",
initailValue = 1,
allocationSize = 50
)
public class PkEx() {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="USER_PK_GENERATOR")
private Long id;
private String name;
}
SEQUENCE 전략도 IDENTITY 전략과 동일한 문제가 있다. 데이터베이스가 직접 기본키를 생성해 주기 때문이다.
EntityManager.persist() 가 호출 되기 전에 기본키를 가져와야 하므로 하이버네이트에서 hibernate: call next value for USER_PK_SEQ 을 실행하여 기본키를 가져온다.
그 후에 EntityManager.persist()호출하기 때문에 IDENTITY 전략과 다르게 쿼리문을 실행하지 않는다.
하지만 SEQUENCE 값을 계속 DB에서 가져와서 사용해야 하기 때문에 성능에 저하를 일으킬 수 있다 . 따라서 allocationSize 의 크기를 적당히 설정하여 성능 저하를 개선시킬 수 있다.
@Entity
@TableGenerator(
name = "USER_PK_GENERATOR",
table = "USER_PK_SEQ",
pkColumnValue = "USER_SEQ",
allocationSize = 1
)
public class PkEx() {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="USER_PK_GENERATOR")
private Long id;
private String name;
}
TABLE 전략은 모든 데이터베이스에서 사용이 가능하지만 최적화 되어있지 않은 테이블을 사용하기 때문에 성능문제에 이슈가 있다.
권장하는 식별키 구성방법 : Long형 + 대체키 + 그에 맞는 적절한 키 생성전략 사용