기본 키 매핑과 @GeneratedValue전략들

박준수·2023년 3월 4일
0

[JPA]

목록 보기
5/14

직접 할당: @Id만 사용

자동 생성(@GeneratedValue: 기본키를 자동으로 생성해준다)

IDENTITY

  • 데이터베이스에 위임
  • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용
  • (예: MySQL의 AUTO_ INCREMENT) -> 데이터베이스가 기본 키를 자동으로 생성
  • IDENTITY 전략은 AUTO_INCREMENT처럼 데이터베이스에 값을 저장하고 나서야 기본 키 값을 구할 수 있을 때 사용한다.
@Entity
public class Member {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

주의점
엔티티가 영속 상태가 되기 위해서는 식별자가 필수입니다.
그런데 IDENTITY 전략을 사용하면 식별자를 데이터베이스에서 지정하기 전까지는 알 수 없기 때문에, em.persist()를 하는 즉시 INSERT SQL이 데이터베이스에 전달됩니다.
따라서 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않습니다.

SEQUENCE

  • 데이터베이스 시퀀스 오브젝트 사용, ORACLE
  • @SequenceGenerator 필요
@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 데이터베이스에서 사용할 수 있습니다.

IDENTITY와 SEQUENCE의 차이

SEQUENCE 전략은 em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회합니다. 그리고 조회한 식별자를 엔티티에 할당한 후, 해당 엔티티를 영속성 컨텍스트에 저장합니다. 이후 트랜잭션 커밋 시점에 플러시가 발생하면 엔티티를 데이터베이스에 저장합니다.
IDENTITY 전략은 먼저 엔티티를 데이터베이스에 저장한 후에 식별자를 조회하여, 엔티티의 식별자에 할당한 후, 영속성 컨텍스트에 저장합니다.

SEQUENCE의 성능 최적화

JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 allocationSize를 사용합니다.
1. 최초 persist() 실행시에 설정에 따른 DB 시퀀스를 두 번 호출하여 첫번째 시퀀스값을 가상으로 관리할 시작값, 두번째 시퀀스 값을 가상으로 관리할 범위의 끝(MAX)값으로 지정합니다.
2. 이후에는 persist()를 실행해도 db에 시퀀스를 호출하지 않고 메모리에서 가상으로 관리하며 할당합니다. persist() 실행시마다 메모리에서 관리하는 가상의 값을 1씩 증가시키며 엔티티에 할당합니다.
3. 어느 시점에 다다르면 엔티티에 식별자를 할당할 값이 관리할 범위의 끝(MAX)이 되고, 이후 다시 한번 persist()를 실행하는 시점에 DB에 시퀀스를 호출합니다.
4. 다시 호출한 시퀀스값을 가상으로 관리할 끝(MAX)값으로 바꾸고 시작값 또한 변경하는데 끝(MAX)값 - (allocationSize - 1) 공식을 사용하 시작값을 정합니다.
참고 : 시퀀스 성능 최적화

이 방법은 시퀀스 값을 선점하므로 여러 JVM에서 동시에 동작해도 기본 키 값이 충돌하지 않는다는 장점이 있습니다. 그러나 데이터베이스에 직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가하므로, 이런 상황이 부담스럽고 INSERT 성능이 중요하지 않다면 allocationSize를 1로 설정하고 사용하면 됩니다.

TABLE

  • @TableGenerator 필요
  • 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략(키 생성용 테이블 사용, 모든 DB에서 사용가능하지만 성능적으로 단점임)
@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;

AUTO

  • 방언에 따라 자동 지정, @GeneratedValue의 strategy의 기본값
  • AUTO로 설정하면 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택
  • DB의 종류도 많고, 기본 키 생성 방식도 다양하기에 해당 전략은 DB를 변경해도 Code 수정을 하지 않아도 되는 장점과,Key 생성 전략이 정해지지 않은 개발 초기 단계나 프로토타입 개발 시에 편리하게 사용할 수 있다.
  • 만약 AUTO를 사용할 때 SEQUENCE나 TABLE 전략이 선택되면, 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 합니다.

참고 : 기본 키 매핑과 전략

권장하는 식별자 전략

기본 키 제약 조건: null 아님, 유일, 변하면 안된다.

  • 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.
  • 예를 들어 주민등록번호도 기본 키로 적절하기 않다.
  • 권장: Long형 + 대체키(Id) + 키 생성전략 사용
profile
방구석개발자

0개의 댓글