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

rara_kim·2022년 12월 12일
0

Spring

목록 보기
18/20

기본키 매핑 방법

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

@Id는 데이터베이스 테이블의 기본 키(PK)와 객체의 필드를 매핑시켜주는 어노테이션이다.
@Id만 사용할 경우엔 기본 키를 직접 할당해 주어야 한다.
기본 키를 직접 할당하는 대신 데이터베이스가 생성해주는 값을 사용하려면 @GeneratedValue를 사용하면 된다.

기본키 자동 생성 전략(4가지)

@GeneratedValue 어노테이션의 strategy속성을 통해 자동 생성 전략을 지정해줄 수 있다.
기본키 자동 생성 전략은 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에서 영속성 컨텍스트에서 객체를 관리하기 위해서는 무조건 ID 속성, 즉 PK 값이 있어야 한다.
(JPA 입장에서는 Map의 key 값이 없다면 해당 객체의 값을 넣을 수 있는 방법이 없기 때문이다.)
그런데 AUTO_INCREMENT 경우 애플리케이션에서는 그 값이 얼마임을 알지 못하기에 DB에 insert문을 날려야 id 값을 알 수 있다.

즉,객체를 save() 메서드로 저장을 할 때 원래는 트랜잭션이 끝나는 COMMIT 시점 전에 flush가 이루어지지만, 해당 경우는 DB에서 id 값을 받아와야 하니 save() 메서드를 호출하는 시점에 insert 쿼리가 나간다. (flush가 이루어진다.)
이렇게 id 값을 할당한 객체는 영속성 컨텍스트 1차 캐시에 값을 넣게된다.

단점으로는 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 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 호출을 최소화할 수 있다.

@SequenceGenerator 속성

속성설명기본 값
name식별자 생성기 이름필수
sequenceName데이터베이스에 등록할 sequence명hibernate_sequence
initalValuesequence 초기 값1
allocationSizesequence 호출 시 증가하는 수,
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=?

모든 데이터베이스에서 사용이 가능하며, 키 생성 전용 테이블을 생성해서 키 값을 관리한다.
최적화되지 않은 테이블에서 키를 생성하기 때문에 성능상의 이슈가 발생할 수 있다.
그래서 실제 서비스에서는 사용하지 않는 것이 좋다.


📚참고
[JPA] 기본 키 생성 전략과 각 전략의 차이 - GenerationType
[JPA] 기본키 자동 생성 전략(Primary Key)

profile
느리더라도 꾸준하게

0개의 댓글