IT/JPA & Hibernate

[JPA] 기본키 자동 생성 전략(Primary Key)

Bamdule 2021. 5. 10. 11:26

1. Goal

1) 기본키 매핑 방법
2) 기본키 자동 생성 전략 4가지

 

2.  기본키 매핑 방법

@Entity
public class User {
    @Id
    private Long id;
}
기본키로 지정하고 싶은 변수에 @Id 어노테이션을 선언하면 해당 컬럼이 기본키로 지정됩니다.

 

3. 기본키 자동 생성 전략 4가지

기본키를 자동으로 생성하려면 @GeneratedValue(strategy = GenerationType.AUTO) 어노테이션을 기본키 변수 위에 선언해주면 됩니다. 기본키 자동 생성 전략은 4 가지가 있으며 전략속성을 생략하면 AUTO 속성으로 지정됩니다.

 

1) AUTO

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
}

 

dialect 값에 따라서 기본키 자동 생성 전략이 지정됩니다. ex) mysql : auto_increment, oracle : sequence ...

 

2) IDENTITY

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}
기본키 생성을 데이터베이스에 위임해 줍니다. 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용하며, AUTO_INCREMENT를 이용해 기본키를 생성합니다.

JPA는 보통 commit 시점에서 모아둔 쿼리들을 DB로 전송합니다. 그런데 AUTO_INCREMENT는 Insert 시 기본키 값이 생성됩니다. AUTO_INCREMENT 사용 시 commit을 하지 않으면 기본키 값을 알 수 없다는 말인데, 이러한 경우 해당 기본키 값을 참조하는 로직이 있거나 영속성 객체를 만들 때 문제가 생깁니다. 그래서 AUTO_INCREMNT를 사용하면 예외적으로 persist 시점에 바로 DB로 쿼리를 전송해 PK 값 생성 후 객체에 저장합니다.

단점으로는 Insert 쿼리를 모아서 한번에 DB로 전송하는 것이 불가능합니다.

 

3) SEQUENCE

@Entity
@SequenceGenerator(
        name = "USER_SEQ_GENERATOR",
        sequenceName = "USER_SEQ", // 시퀸스 명
        initialValue = 1, // 초기 값
        allocationSize = 1 // 미리 할당 받을 시퀸스 수
)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ_GENERATOR")
    private Long id;
}

// create sequence USER_SEQ start with 1 increment by 1
    # 키 생성 및 초기화
    create table USER_SEQ (
       next_val bigint
    ) engine=InnoDB

    insert into USER_SEQ values ( 1 )
    
    # 키 조회    
    select
        next_val as id_val 
    from
        USER_SEQ for update
         
    # 키 업데이트
    update
        USER_SEQ 
    set
        next_val= ? 
    where
        next_val=?
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트입니다.
(오라클, PostgreSQL, DB2, H2, MariaDB (10.3 버전 이상) 에서 사용가능)

단점은 persist 시 next sequence를 DB에서 발급 받으며, 이는 잦은 DB 호출로 인한 성능 저하로 연결될 수 있습니다.
그래서 allocationSize 속성을 통해 최대한 DB호출을 줄여야합니다.

장점은 쓰기지연을 통해 SQL 쿼리를 commit시 한번에 DB로 전송해 DB 호출을 최소화할 수 있습니다.
속성 설명 기본 값
name 식별자 생성기 이름 필수
sequenceName 데이터베이스에 등록할 sequence 명 hibernate_sequence
initalValue sequence 초기 값 1
allocationSize sequence 호출 시 증가하는 수,
jpa는 sequence를 증가 시키다가 할당 받은 sequence를 모두 소모하면 db에 접근하여 sequence를 할당 받을 만큼 증가 시킨다. (성능 최적화를 위해 사용됨)
50
catalog, schema 데이터베이스 catalog, schema 이름  

 

4) TABLE

@Entity
@TableGenerator(
        name = "USER_SEQ_GENERATOR",
        table = "MY_SEQUENCES",
        pkColumnValue = "USER_SEQ",
        allocationSize = 1
)
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "USER_SEQ_GENERATOR")
    private Long id;
}
    create table MY_SEQUENCES (
       sequence_name varchar(255) not null,
        next_val bigint,
        primary key (sequence_name)
    ) engine=InnoDB
    
    
    insert into MY_SEQUENCES(sequence_name, next_val) values ('USER_SEQ',0)
    
    # 키 조회
    select
        tbl.next_val 
    from
        MY_SEQUENCES tbl 
    where
        tbl.sequence_name=? for update
    
    # 키 업데이트    
    update
        MY_SEQUENCES 
    set
        next_val=?  
    where
        next_val=? 
        and sequence_name=?
모든 데이터베이스에서 사용이 가능하며, 키 생성 전용 테이블을 생성해서 키 값을 관리합니다.
최적화되지 않은 테이블에서 키를 생성하기 때문에 성능상의 이슈가 발생할 수 있습니다. 그래서 상용 서비스에서 사용하지 않는 것이 좋습니다.

참조 : 인프런 - 자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한님)