@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
주의점
엔티티가 영속 상태가 되기 위해서는 식별자가 필수입니다.
그런데 IDENTITY 전략을 사용하면 식별자를 데이터베이스에서 지정하기 전까지는 알 수 없기 때문에, em.persist()를 하는 즉시 INSERT SQL이 데이터베이스에 전달됩니다.
따라서 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않습니다.
@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;
@SequenceGenerator를 사용하여 시퀀스 생성기를 등록한 후, @GeneratedValue의 generator 속성으로 시퀀스 생성기를 선택하였습니다.
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트입니다.
SEQUENCE 전략은 이 시퀀스를 사용해서 기본 키를 생성합니다.
이 전략은 시퀀스를 지원하는 오라클, PostgreSQL, H2 데이터베이스에서 사용할 수 있습니다.
SEQUENCE 전략은 em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회합니다. 그리고 조회한 식별자를 엔티티에 할당한 후, 해당 엔티티를 영속성 컨텍스트에 저장합니다. 이후 트랜잭션 커밋 시점에 플러시가 발생하면 엔티티를 데이터베이스에 저장합니다.
IDENTITY 전략은 먼저 엔티티를 데이터베이스에 저장한 후에 식별자를 조회하여, 엔티티의 식별자에 할당한 후, 영속성 컨텍스트에 저장합니다.
JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 allocationSize를 사용합니다.
1. 최초 persist() 실행시에 설정에 따른 DB 시퀀스를 두 번 호출하여 첫번째 시퀀스값을 가상으로 관리할 시작값, 두번째 시퀀스 값을 가상으로 관리할 범위의 끝(MAX)값으로 지정합니다.
2. 이후에는 persist()를 실행해도 db에 시퀀스를 호출하지 않고 메모리에서 가상으로 관리하며 할당합니다. persist() 실행시마다 메모리에서 관리하는 가상의 값을 1씩 증가시키며 엔티티에 할당합니다.
3. 어느 시점에 다다르면 엔티티에 식별자를 할당할 값이 관리할 범위의 끝(MAX)이 되고, 이후 다시 한번 persist()를 실행하는 시점에 DB에 시퀀스를 호출합니다.
4. 다시 호출한 시퀀스값을 가상으로 관리할 끝(MAX)값으로 바꾸고 시작값 또한 변경하는데 끝(MAX)값 - (allocationSize - 1) 공식을 사용하 시작값을 정합니다.
참고 : 시퀀스 성능 최적화
이 방법은 시퀀스 값을 선점하므로 여러 JVM에서 동시에 동작해도 기본 키 값이 충돌하지 않는다는 장점이 있습니다. 그러나 데이터베이스에 직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가하므로, 이런 상황이 부담스럽고 INSERT 성능이 중요하지 않다면 allocationSize를 1로 설정하고 사용하면 됩니다.
@Entity
@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;
참고 : 기본 키 매핑과 전략
기본 키 제약 조건: null 아님, 유일, 변하면 안된다.