twocowsong

SEQUENCE 전략 본문

IT/JPA

SEQUENCE 전략

WsCode 2022. 5. 14. 22:56

깃허브 정리 URL : https://github.com/sWineTake/jpa.git

 

GitHub - sWineTake/jpa: 자바 ORM 표준 JPA 프로그래밍 - 김영한

자바 ORM 표준 JPA 프로그래밍 - 김영한. Contribute to sWineTake/jpa development by creating an account on GitHub.

github.com

DB 시퀀스는 유일한 값을 순서대로 생성하는 특별한 DB 오브젝트 입니다.

SEQUENCE 전략은 이 시퀀스를 사용해서 기본키를 생성합니다.

 

MYSQL에서는 SEQUENCE 전략이 사용이 불가능하여 본 글에서는 H2 DB로 개발을 진행하겠습니다.

H2 데이터베이스에서 아래와 같이 DDL문을 입력해주세요.

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

CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;

시퀀스 매핑 엔티티는 소스코드는 아래와 같습니다.

@Getter
@Entity
@SequenceGenerator(
      name = "BOARD_SEQ_GENERATOR",
      sequenceName = "BOARD_SEQ", // 매핑할 DB 시퀀스 이름
      initialValue = 1,
      allocationSize = 1
)
public class Board {
   @Id
   @GeneratedValue(strategy = GenerationType.SEQUENCE,
               generator = "BOARD_SEQ_GENERATOR")
   private Long id;
}

사용할 DB 시퀀스를 매핑을 해야합니다.

@SequenceGenerator를 사용해서 "BOARD_SEQ_GENERATOR" 라는 시퀀스 생성기를 등록하였습니다.

그리고 sequenceName 속성의 이름으로 "BOARD_SEQ"를 지정했는데 JPA는 이 시퀀스 생성기를 실제 DB BOARD_SEQ 시퀀스와 매핑합니다.

 

다음으로 키 생성 전략을 GenerationType.SEQUENCE로 설정하고 generator = "BOARD_SEQ_GENERATOR"로 방금 등록한 시퀀스 생성기를 선택하였습니다.

이제부터 id식별자 값은 BOARD_SEQ_GENERATOR시퀀스 생성기가 할당합니다.

Board board = new Board();
em.persist(board);
System.out.println("board.id : " + board.getId());

여기서 SEQUENCE 전략의 차이점이 나타납니다. 

em.persist()를 호출전 먼저 DB시퀀스를 사용해서 식별자를 조회합니다.

그리고 조회한 식별자를 엔티티에 할당 한 후에 엔티티를 영속성 컨텍스트에 저장합니다.

(영속성 컨텍스트 특징 중 한가지는 식별자 값을 가집니다.)

이후 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 DB에 저장합니다.

 

반대로 이전에 설명했던 IDENTITY전략은 먼저 엔티티를 DB에 저장한 후에 식별자를 조회해서 엔티티의 식별자에 할당합니다.

 


@SequenceGenerator의 속성 중 allocationSize의 기본값이 50입니다.

JPA가 기본으로 생성하는 DB시퀀스는  create sequence [sequenceName] start with 1 increment by 50이므로 시퀀스를 호출할때마다 50씩 증가합니다. 기본값이 50인 이유는 최적화 때문입니다.

 

SEQUENCE 전략은 DB 시퀀스를 통해 식별자를 조회하는 추가 작업이 필요합니다. 따라서 DB와 2번 통신을 합니다. 

1. 식별자를 구하려고 DB 시퀀스를 조회합니다.

SELECT BOARD_SEQ.NEXTVAL FROM DUAL

2. 조회한 시퀀스를 기본 키 값으로 사용해 DB에 저장합니다.

INSERT INTO BOARD ...

JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 @SequenceGenerator.allocationSize를 사용합니다.

한번에 DB 시퀀스 값을 증가시키고 나서 그만큼 메모리에 시퀀스 값을 할당합니다. 

예를들어 allocationSize 값이 50이면 시퀀스를 한 번에 50 증가 시킨 다음에 1~50까지는 메모리에 식별자를 할당합니다. 그리고 51이 되면 시퀀스 값을 100으로 증가시킨 다음 51 ~ 100까지 메모리에 식별자를 할당합니다.

 

이 최적화 방법은 시퀀스 값을 선점하므로 여러 JVM이 동시에 동작해도 기본 키 값이 충돌하지 않습니다.

반면에 DB에 직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가한다는 점을 염두하셔야 합니다.

꼭 persistence.xml 파일의 아래의 속성을 true를 해주셔야지만 지금까지의 최적화 방법이 적용됩니다.

<!-- 키 생성 전략 사용시 true -->
<property name="hibernate.id.new_generator_mappings" value="true" />

 

위 상황이 부담스럽고 INSERT 성능이 중요하지 않으면 allocationSize의 값을 1로 설정하면 됩니다.

 

'IT > JPA' 카테고리의 다른 글

AUTO 전략  (0) 2022.05.16
TABLE 전략  (0) 2022.05.15
IDENTITY 전략  (0) 2022.05.13
기본 키 직접 할당 전략  (0) 2022.05.13
기본키 매핑 - 기본 키 생성 전략  (0) 2022.05.11