코딩과 결혼합니다

[JPA] 기본키 생성 전략 본문

2세/JPA

[JPA] 기본키 생성 전략

코딩러버 2024. 2. 12. 14:23
728x90

기본키를 맵핑하는 방법으로는 크게 3가지가 있다.

 

1. 단일 키 맵핑

한 개의 컬럼만을 기본키로 사용하는 방법. 

 

@Id

@Entity
public class Member {
    @Id
    private String id;

    // 나머지 필드들...
}

// 엔티티 사용 예시
Member member = new Member();
member.setId("myId"); // 직접 아이디 할당
entityManager.persist(member);

개발자가 직접 기본키를 할당하는 방식이다. 이 방식은 기본키 값을 애플리케이션 로직에서 제어해야 할 때 주로 사용한다.

특정 규칙에 따라 기본키를 생성하거나, 사용자가 직접 아이디를 입력하는 경우 등에 유용하다.

 

그러나 직접 관리를 해야 하므로 코드가 복잡해질 수 있다. (기본 키 중복 방지를 위한 로직이 따로 필요)

데이터 생성 전에 아이디를 미리 준비해야 해서 이로 인해 성능 저하가 발생할 수 있다.

더보기

예를 들어, 많은 양의 데이터를 한 번에 처리해야 하는 배치 작업 등에서는 각 데이터마다 고유한 아이디를 미리 생성해두어야 합니다. 이때 아이디 생성 작업이 복잡하거나, 아이디 생성을 위한 추가적인 DB 접근(예: 기존 아이디 확인)이 필요하다면, 전체 작업의 성능에 영향을 줄 수 있습니다.

또한, 아이디를 미리 생성해두지 않았을 때, 데이터를 DB에 저장하는 시점에서 아이디가 없어서 저장에 실패하는 등의 문제가 발생할 수 있습니다. 이런 문제를 방지하기 위해 데이터를 생성하기 전에 아이디를 미리 할당해야 하는데, 이 과정은 추가적인 처리 시간이 필요하므로 성능 저하를 일으킬 수 있습니다.

따라서 직접 할당 방식을 사용할 때에는 이런 점들을 고려하여 설계를 해야 합니다.

@GeneratedValue

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO) // 자동 생성
    private Long id;
    //...
}

JPA가 제공하는 전략을 이용하여 기본키를 자동으로 생성하는 방식. AUTO, IDENTITY, SEQUENCE, TABLE, UUID 등이 있다.

 

  • AUTO
    DB 방언에 맞춰서 자동으로 생성. 즉, 특정 DB에 의존하지 않고 JPA가 실행 환경에 따라 자동으로 기본키 생성 전략을 결정한다. 예를 들어, Hibernate의 경우 DB Dialect 설정에 따라 시퀀스, 아이덴티티, 테이블 등의 전략을 선택한다.

    - DBMS에 따라 기본키 전략을 결정하므로, DBMS가 바뀔 경우 예상치 못한 결과가 발생할 수 있다.

  • IDENTITY
    데이터베이스가 자동으로 ID를 생성하도록 하는 방식. INSERT 문장이 실행될 때에 데이터베이스에서 자동으로 값을 생성하며, 이 때문에 트랜잭션과 무관하게 독립적으로 실행된다.

    - 이 전략은 간단하고 효율적이지만, 트랜잭션의 일관성을 해칠 수 있다.
    - 엔티티를 저장하는 즉시 SQL이 실행되므로 성능 최적화 기번인 JDBC의 BATCH SQL 기능을 사용 
    - DBMS에 따라 지원 여부가 다르므로 DBMS를 변경할 경우 수정이 필요할 수 있다.

  • SEQUENCE
    데이터베이스의 시퀀스를 통해 ID를 생성하는 방식이다. 이 전략을 사용하면 트랜잭션을 커밋하는 시점에 일관적
    으로 SQL이 실행될 수 있다. 성능 최적화나 세세한 트랜잭션 제어가 필요한 경우에는 이 전략이 더 유리할 수 있다.

    - 이 전략은 높은 성능과 동시성을 제공하나 몇 가지 단점이 존재한다.
    - 시퀀스는 Oracle, PostgreSQL, DB2, H2 등 일부 DBMS에서만 지원한다.
    (MySQL 8.0 이상에서는 시퀀스를 흉내 낼 수 있는 기능이 추가되었지만, 아직까지는 아이덴티티 전략을 더 일반적으로 사용) 
    - 시퀀스는 DB에 별도의 오브젝트로 존재하므로, 이를 관리해야 한다. (초기값, 증가값 설정)

    - 시퀀스는 자동으로 값을 증가시켜, 이 과정에서 값의 낭비가 발생할 수 있다.

  • TABLE
    별도의 키 생성 테이블을 만들어 데이터베이스 기본키를 생성. 모든 DBMS에서 사용할 수 있으므로, DBMS에 독립적인 전략을 원할 때 사용한다. 

    - 키 생성을 위해 매번 추가적인 셀렉트, 업데이트 SQL이 실행되므로 성능 이슈가 발생할 수 있어 주의가 필요하다.
  • UUID
    모든 환경에서 유일한 식별자를 생성하는 방식. 128비트의 랜덤한 값으로, 데이터베이스 간 충돌 없이 고유한 값을 생성할 수 있다. 이는 분산 환경에서 매우 유용하다. 예를 들어, 여러 서버나 DB에서 동시에 데이터를 생성하더라도 UUID를 통해 각 데이터를 고유하게 식별할 수 있다.

    - 길이가 길고, 숫자보다 문자열로 저장되므로 저장 공간이 더 필요하고, 인덱스 성능이 떨어질 수 있다.

2. 복합 키 맵핑

둘 이상의 컬럼을 기본키로 사용하는 방법

 

@IdClass

@Entity
@IdClass(MemberId.class)
public class Member {
    @Id
    private String id;
    
    @Id
    private String email;
    //...
}

public class MemberId implements Serializable {
    private String id;
    private String email;
    //...
}

 

@ EmbeddedId

@Entity
public class Member {
    @EmbeddedId
    private MemberId id;
    //...
}

@Embeddable
public class MemberId implements Serializable {
    private String id;
    private String email;
    //...
}

 

3. 비식별 관계 맵핑

부모 테이블의 기본키를 자식 테이블의 일반 컬럼으로 포함하는 방법

 

@MapsId

@Entity
public class Parent {
    @Id
    @GeneratedValue
    private Long id;
    //...
}

@Entity
public class Child {
    @Id
    private Long id;
    
    @MapsId
    @OneToOne
    @JoinColumn(name = "PARENT_ID")
    private Parent parent;
    //...
}