JPA 기본 키 생성 전략 - xx10222/selab-todo-list GitHub Wiki

image

기본 키 매핑 방법

@Entity
public class User {
    @Id
    private Long id;
}

기본키도 저장하고 싶은 변수에 @Id 어노테이션을 선언하면 해당 컬럼이 기본키로 지정된다

기본키 자동 생성 전략

기본키를 자동으로 생성하려면 @GeneratedValue(startegy = 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. IDENTIFY

@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_INCREMENT 를 사용하면 예외적으로 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 호출을 최소화할 수 있다

image


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=?
  • 모든 데이터베이스에서 사용이 가능하며, 키 생성 전용 테이블을 생성해서 키 값을 관리한다
  • 최적화되지 않은 테이블에서 키를 생성하기 때문에 성능상의 이슈가 발생할 수 있다
  • 그래서 상용 서비스에서 사용하지 않는 것이 좋다
⚠️ **GitHub.com Fallback** ⚠️