JPA가 제공하는 기본 키 생성 전략

  • 직접 할당 전략 : 기본 키애플리케이션에서 직접 할당합니다.
  • 자동 생성 전략 : 대리 키를 사용하는 방식으로 IDENTITY, SEQUENCE, TABLE 전략이 있습니다.
    1. IDENTITY : 기본 키 생성을 데이터베이스위임하는 방식입니다.
    2. SEQUENCE : 데이터베이스시퀀스를 사용해서 기본 키할당하는 방식입니다.
    3. TABLE : 키 생성 테이블을 이용하는 방식입니다.
자동 생성 전략을 사용하려면 persistence.xmlhibernate.id.new_generator_mappings = true 속성을 추가해야 합니다. 이는 하이버네이트에서 JPA 규격에 맞으며 더 효과적으로 개발한 새로운 키 생성 전략이며 과거 버전과의 호환성유지를 위해 기본값false속성입니다. 이 옵션을 설정하면 키 생성 성능최적화하는 allocationSize 속성을 사용하는 방식이 달라진다고 합니다. 

 

기본 키 직접 할당 전략

  • 기본 키직접 할당하기 위해서는 @Id만 사용하여 매핑해줍니다.
  • @Id 적용 가능한 자바 타입은 다음과 같습니다. 
    • 자바 기본형
    • 자바 래퍼( Wrapper )형
    • String
    • java.util.Date
    • java.math.BigDecimal
    • java.math.BigInteger
  • em.persist( )엔티티저장하기 전에 애플리케이션에서 기본 키직접 할당하는 방법입니다. 
Member member = new Member();
member.setId("member1");	// 기본 키 직접 할당
em.persist(member);

 

IDENETITY 전략

  • IDENTITY기본 키 생성데이터베이스위임하는 전략입니다.
  • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용합니다. 
  • @GeneratedValue 어노테이션을 사용하여 식별자 생성 전략IDENTITY로 선택합니다. 
  • 데이터베이스에 값을 저장할 때 ID 컬럼을 비워두면 데이터베이스식별자 값을 생성하여 채워줍니다.
  • 이 전략을 사용하는 경우, JPA기본 키 값을 얻어오기 위하여 데이터베이스추가로 조회합니다. 
@Entity
public class Member{
	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)	// IDENTITY 속성을 사용
    	private Long id;
    	...
}
- IDENTITY 전략을 사용하는 경우 데이터를 데이터베이스INSERT한 후에 기본키 값을 조회할 수 있습니다. 따라서, 엔티티식별자 할당하려면 DB추가로 조회해야 합니다.
- JDBC3에 추가된 Statement.getGeneratedKeys( )를 사용하여 데이터베이스 저장과 동시에 기본 키 값을 얻어 올 수 있습니다. 하이버네이트는 이 메서드를 이를 사용하여 데이터베이스한 번만 통신합니다.
- 엔티티영속상태가 되려면 식별자가 반드시 필요합니다. IDENTITY 전략을 사용하는 경우 식별자 값매핑하기 위해 em.persist( )호출하는 즉시 INSERT SQL이 데이터베이스에 전달됩니다. 따라서 이 전략트랜잭션을 지원하는 쓰기 지연이 동작하지 않습니다.

 

SEQUENCE 전략

  • 데이터베이스 시퀀스유일한 값순서대로 생성하는 데이터베이스 오브젝트입니다.
  • SEQUENCE 전략은 시퀀스를 사용하여 기본 키생성하는 전략입니다.
  • 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있습니다.

SEQUENCE 전략을 사용하는 방법

1. 데이터베이스에 시퀀스 생성

CREATE TABLE BOARD{
	ID BIGINT NOT NULL PRIMARY KEY,
    DATA VARCHAR( 255 )
}

// 시퀀스 생성하기
CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;	// 1부터 1씩 증가하며 할당합니다.

2. 데이터베이스의 시퀀스와 엔티티 매핑

@Entity
@SequenceGenerator(
	name = "BOARD_SEQ_GENERATOR",	// 시퀀스 생성기 이름 
    	sequenceName = "BOARD_SEQ",	// 매핑할 데이터베이스 시퀀스 이름
    	initialValue = 1, allocationSize = 1)
public class Board{
	@Id
    	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOARD_SEQ_GENERATOR")
	private Long id;
    ...
}
  • @SequenceGenerator을 사용하여 BOARD_SEQ_GENERATOR 시퀀스 생성기등록하였습니다.
  • sequenceName 속성을 사용하여 실제 데이터베이스의 시퀀스BOARD_SEQ 시퀀스매핑합니다.
  • 키 생성 전략GenerationType.SEQUENCE로 설정하고 generator 속성으로 방금 생성한 시퀀스 생성기를 선택합니다.
SEQUENCE 전략은 em.persist( )호출할 때 먼저 데이터베이스 시퀀스를 이용하여 식별자조회합니다.
그리고 조회한 식별자 엔티티할당한 후 엔티티영속성 컨텍스트저장합니다.
이후 트랜잭션커밋해서 플러시가 일어나면 엔티티데이터베이스저장합니다.
이와 달리 IDENTITY 전략은 엔티티데이터베이스저장한 후 식별자조회해서 엔티티식별자할당합니다.

@SequenceGenerator

속성 기능 기본값
name 식별자 생성기 이름 필수
sequenceName 데이터베이스에 등록되어 있는 시퀀스 이름 hibernate_sequence
initialValue DDL 생성 시에만 사용됨. 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다. 1
allocationSize 시퀀스 한 번 호출에 증가하는 수
( 성능 최적화에 사용됨 )
50
catalog, schema 데이터베이스 catalog, schema 이름  

SEQUENCE 전략과 최적화

  • SEQUENCE 전략은 데이터베이스 시퀀스를 통해 식별자조회하는 추가 작업이 필요합니다. 따라서 데이터베이스2번 통신합니다. 
  • JPA시퀀스접근하는 횟수를 줄이기 위해 @SequenceGenerator.allocationSize를 사용합니다.
  • allocationSize50인 경우 시퀀스를 한 번에 50 증가시킨 다음 1 ~ 50까지는 메모리에서 식별자할당합니다. 이후 51이 되면 시퀀스의 값을 100으로 증가시킨 이후 51 ~ 100까지 메모리에서 식별자할당하여 최적화를 수행합니다.
  • 이 방법은 시퀀스 값을 선점하므로 여러 JVM이 동시에 동작해도 기본 키 값이 충돌하지 않는다는 장점이 있지만, 데이터베이스직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가한다는 점을 염두해두어야 합니다.
    이런 상황이 부담스럽고, INSERT 성능이 중요하지 않은 경우 allocationSize 값을 1로 설정하면 됩니다.
  • 최적화 방법은 hibernate.id.new_generator_mappings 속성을 true로 설정해야 적용되며, 설정하지 않는 경우 과거 hibernate가 사용하던 최적화 방법을 사용합니다.
    ( 과거에는 시퀀스 값을 하나씩 할당받고 애플리케이션에서 allocationSize 만큼 사용했습니다. ) 

 

TABLE 전략

  • TABLE 전략은 키 생성 전용 테이블을 하나 만들고 여기에 이름으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략입니다.

TABLE 전략을 사용하는 방법

1. 데이터베이스에 키 생성 용도로 사용할 테이블 생성

CREATE TABLE MY_SEQUENCES (
	sequence_name varchar(255) not null,	// 시퀀스 이름으로 사용
    	next_val bigint,			// 시퀀스 값으로 사용
    	primary key ( sequence_name )
)

2. 데이터베이스의 테이블과 엔티티 매핑

@Entity
@TableGenerator(			// 테이블 키 생성기 등록
	name = "BOARD_SEQ_GENERATOR",	// 테이블 키 생성기 이름
    	table = "MY_SEQUENCES",		// 키 생성용 테이블과 매핑
    	pkColumnValue = "BOARD_SEQ", allocationSize = 1	// 시퀀스 값 컬럼명        )
public class Board{
	
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR" )
    private Long id;
    ...
}

 

  • TABLE 전략은 시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식같습니다.
  • 키 생성 용도 테이블에 키로 사용할 값 이름으로 BOARD_SEQ 시퀀스 으로는 식별자 값이 들어갑니다. 

@TableGenerator

속성 기능 기본값
name 식별자 생성기 이름 필수
table 키 생성 테이블 명 hibernate_sequences
pkColumnName 시퀀스 컬럼명 sequence_name
valueColumnName 시퀀스 값 컬럼명 next_val
pkColumnValue 키로 사용할 값 이름 엔티티 이름
initialValue 초기 값, 마지막으로 생성된 값이 기준이다. 0
allocationSize 시퀀스 한 번 호출에 증가하는 수 ( 성능 최적화에 사용됨 ) 50
catalog, schema 데이터베이스 catalog, schema 이름  
uniqueConstraints(DDL) 유니크 제약 조건을 지정할 수 있다.  
TABLE 전략은 값을 조회하면서 SELECT 쿼리를 사용하고 다음 값으로 증가시키기 위해 UPDATE 쿼리를 사용합니다. 이 전략은 SEQUENCE 전략과 비교해서 데이터베이스에 한 번 더 통신하는 단점이 있습니다.
TABLE 전략을 최적화하는 방법은 @TableGenerator.allocationSize를 사용할 수 있습니다.
이를 사용한 최적화 방법은 SEQUENCE 전략과 같습니다.

 

AUTO 전략

  • AUTO 전략은 선택한 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택합니다. ( 오라클을 선택하면 SEQUENCE, MySQL을 선택하면 IDENTITY를 사용합니다. )  
  • @GeneratedValue기본 값AUTO이며, 데이터베이스변경해도 코드수정할 필요가 없다는 장점을 가지고 있습니다.
  • 키 생성 전략이 아직 확정되지 않은 개발 초기 단계프로토타입 개발 시 편리하게 사용할 수 있습니다.
  • AUTO를 사용할 때 SEQUENCETABLE 전략이 선택되면 시퀀스키 생성용 테이블을 미리 만들어 두어야 하며, 스키마 자동 생성 기능을 사용한다면 하이버네이트 기본값을 사용하여 적절한 시퀀스키 생성 테이블을 만들어 줄 것입니다.

 

권장하는 식별자 선택 전략

  • 데이터베이스 기본 키는 다음 3가지 조건모두 만족해야 합니다.
    1. null 값은 허용하지 않는다.
    2. 유일해야 한다.
    3. 변해선 안 된다.
  • 테이블 기본 키를 선택하는 전략은 크게 2가지가 있습니다.
    1. 자연 키 ( natural key )
      • 비즈니스에 의미가 있는 키 ( 주민등록번호, 이메일 , 전화번호 등 )
    2. 대리 키 ( surrogate key )
      • 비즈니스와 관련 없는 임의로 만들어진 키, 대체 키로도 불립니다.
      • ( 오라클 시퀀스, auto_increment, 키 생성 테이블 사용 )
자연 키의 경우 미래에 예측할 수 없는 요구사항이나 비즈니스의 변경
( 정책이 변하여 주민등록번호를 저장하지 못하는 등 )으로 인해 기본 키의 조건을 만족하지 못할 수 있습니다
따라서, 비즈니스무관한 임의의 값 대리 키를 사용하는 것을 권장합니다. 

'JPA' 카테고리의 다른 글

[ JPA ] 영속성 컨텍스트와 엔티티 생명주기  (0) 2023.08.01

+ Recent posts