항해99

항해99 63일차 TIL1 - JPA 기본키 생성 전략 IDENTITY, SEQUENCE

자몽포도 2023. 2. 20. 23:00

2023-05-28 수정 시작

보시는 분들이 조금 계신 것 같아서 혹여나 도움이 되실까봐 링크 남기겠습니다. 

JPA - 기본 키 매핑 IDENETITY vs SEQUNECE 이 글과 비슷한 글이지만 조금 더 정돈해서 글을 작성했습니다.

추가로 MySQL(Inno DB 스토리지 엔진) 환경에서 두 기본키 전략을 비교하였습니다.

2023-05-28 수정 종료


엔티티는 @GeneratedValue 애노테이션을 통해 기본키 생성 전략을 결정할 수 있습니다.

GenerateType 은 AUTO, SEQUENCE, IDENTITY, TABLE 네 가지가 있습니다. 이 중에서 SEQUENCE, IDENTITY 두 가지를 알아보도록 하겠습니다.

참고로 테스트에 사용된 DB는 H2입니다. 

 

IDENTITY


IDENTITY는 기본 키 생성을 데이터베이스에 위임합니다. MYSQL을 데이터베이스로 사용할 경우, AUTO_INCREMEMT가 적용된다고 하네요. H2에서도 비슷한 전략이 사용되는 것 같습니다.

 

실제 데이터베이스를 보면 아래와 같이 구성되어 있습니다.

 

데이터가 입력될 때는 아래와 같이 INSERT 쿼리가 나갑니다.

 

IDENTITY 전략의 장점은 데이터를 저장할 때 단 한 번의 INSERT 쿼리만 나간다는 점입니다.

반면 JPA의 쓰기 지연을 사용할 수 없는 특징이 있습니다. 

 

public BulletinBoardDto create(BulletinBoardForm boardForm) {
    BulletinBoard board1 = new BulletinBoard(boardForm);
    BulletinBoard board2 = new BulletinBoard(boardForm);

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    em.persist(board1);
    System.out.println("================");
    em.persist(board2);

    tx.commit();

 

위와 같은 로직이 실행될 때 쿼리는 아래와 같이 persist 실행될 때 마다 INSERT 쿼리가 나가게 됩니다. 그렇기 때문에 printIn 문이 persist 사이에 존재하게 됩니다.

 

쓰기 지연이 동작하지 않는 이유는 엔티티가 영속 상태가 아니기 때문이다. 엔티티는 영속 상태가 되려면 식별자가 필요하다. 하지만 IDENTITY 전략의 경우 데이터를 저장해야 기본키(식별자)가 만들어지게 된다. 그래서 persist 시점에서 영속 상태가 될 수 없다.

 

SEQUENCE


데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다. SEQUNECE 전략을 사용해서 테이블을 만들면 IDENTITY에서는 볼 수 없었던 것이 하나 생성된다.

 

 

public BulletinBoardDto create(BulletinBoardForm boardForm) {
    BulletinBoard board1 = new BulletinBoard(boardForm);
    BulletinBoard board2 = new BulletinBoard(boardForm);

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    em.persist(board1);
    System.out.println("================");
    em.persist(board2);

    tx.commit();

 

그리고 아까와 같이 데이터를 INSERT 하는 로직을 실행시키면 아래와 같이 쿼리가 나가게 됩니다.

 

 

한 번의 persist에 두 번의 쿼리가 나가게 됩니다. 그리고 쓰기지연 기능이 동작하는 것을 볼 수 있습니다. printIn 문이 먼저 실행되고 INSERT 쿼리가 그 다음에 나간것이 그 증거입니다.

 

SEQUENCE 전략의 경우 시퀀스를 조회해서 먼저 식별자 값을 가져옵니다. 그렇기 때문에 INSERT 시점에서 엔티티가 영속 상태가 될 수 있습니다. 다만 INSERT 마다 쿼리가 두 번 나간다는 단점?이 있는데요. 이를 보완하기 위해 @SequenceGenerator 에는 allocationSize 라는 파라미터가 존재합니다. allocationSize를 지정한 만큼 데이터베이스를 커넥션하지 않고 메모리에서 기본키를 조회합니다.

 

allocationSize를 3로 설정하고 데이터를 저장해보겠습니다.

아까와는 다르게 3번에 한 번 씩 시퀀스를 조회하기 위해 데이터 베이스에 접근하는 것을 볼 수 있습니다. 정리하면 SEQUENCE 전략의 경우, 쓰기 지연 기능을 사용할 수 있다는 점과 INSERT 쿼리 시, 쿼리가 여러번 나갈 수 있다는 점이 있습니다. SEQUENCE 전략을 사용한 사례로 우아한 형제들 기술 블로그의 HikariCP Dead lock에서 벗어나기 (실전편)

를 남기도록 하겠습니다.