Posts [자바 ORM 표준 JPA 프로그래밍-기본편] 기본키 매핑
Post
Cancel

[자바 ORM 표준 JPA 프로그래밍-기본편] 기본키 매핑

본 포스팅은 인프러의 JPA 기본편을 수강하고 정리하는 내용입니다.


기본 키 매핑 어노테이션

  • @Id
  • @GeneratedValue
1
2
3
4
5
6
@Entity
class Product {
  @Id @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  ...
}

기본 키 매핑 방법

  • 직접 할당: @Id 만 사용
  • 자동 생성(@GeneratedValue)
    • IDENTITY: 데이터베이스에 위임, MYSQL
    • SEQUENCE: 데이터베이스 시퀀스 오브젝트 사용, ORACLE
      • @SequenceGenerator 필요
    • TABLE: 키 생성용 테이블 사용, 모든 DB에서 사용
      • @TableGenerator 필요
    • AUTO: 방언에 따라 자동 지정, 기본값

IDENTITY 전략 - 특징

  • 기본 키 생성을 데이터베이스에 위임
  • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용
    • (예: MySQL의 AUTO_ INCREMENT)
  • JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL 실행
  • AUTO_ INCREMENT는 데이터베이스에 INSERT SQL을 실행한 이후에 ID 값을 알 수 있음
    • DB에 엔티티가 저장된 후에야 id를 알 수 있다보니 1차 캐시에 id값은 null이 되게됨
  • IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회
    • jdbc드라이버에 insert 쿼리를 실행 후 내부적으로 id값을 리턴받는게 별도로 있다. JPA가 이를 사용하여 실행한다.
    • 그래서 모아서 insert 하는게 IDENTITY 전략에선 불가능하다. (단점)
    • 하지만 버퍼링해서 write하는게 크게 메리트가 있진 않다.
1
2
3
4
5
6
7
@Entity
public class Member {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  ...
}

SEQUENCE 전략 - 특징

  • 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트(예: 오라클 시퀀스)
  • 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
@SequenceGenerator(
name = “MEMBER_SEQ_GENERATOR",
sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름 (테이블 별로 시퀀스를 별도로 가져갈때 설정)
initialValue = 1, allocationSize = 1)
public class Member {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE,
  generator = "MEMBER_SEQ_GENERATOR")
  private Long id;
  
  ...
}

JPA가 persist()를 호출할때 시퀀스 전략일 경우 db에서 먼저 sequence를 불러와서 엔티티에 세팅한다. 실제 커밋하는 시점에 버퍼에 쌓인 쿼리를 한 번에 실행한다.

image

Note: 매번 네트워크를 왔다갔다해서 성능상 좋지 않나라는 고민을 할 수 있다. allocationSize 를 속성을 통해 최적화를 할 수 있다. 예를 들어, allocationSize를 50으로 지정할 경우 한 번 호출할때 DB에는 시퀀스 값을 50 증가시킨다. 그리고 메모리에 그 50만큼 가지고 있으면서 쓰는 방식이다. 이를 통해 네트워크를 통해 시퀀스를 매번 받아오는 이슈를 줄일 수 있다.

1
2
3
em.persist(member1); // DB SEQ = 1  | 1 , DB SEQ = 51  | 1
em.persist(member2); // DB SEQ = 51  | 2
em.persist(member3); // DB SEQ = 51  | 3

@SequenceGenerator - 속성

주의!: allocationSize 기본값 = 50

image

TABLE 전략

  • 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략
  • 장점: 모든 데이터베이스에 적용 가능
  • 단점: 성능(테이블을 직접 사용하다보니 락이 걸릴 수도 있기에..)
1
2
3
4
5
create table MY_SEQUENCES (
  sequence_name varchar(255) not null,
  next_val bigint,
  primary key ( sequence_name )
)
1
2
3
4
5
6
7
8
9
10
11
12
@Entity
@TableGenerator(
  name = "MEMBER_SEQ_GENERATOR",
  table = "MY_SEQUENCES",
  pkColumnValue = “MEMBER_SEQ", allocationSize = 1)
public class Member {
  @Id
  @GeneratedValue(strategy = GenerationType.TABLE,
  generator = "MEMBER_SEQ_GENERATOR")
  private Long id;
  ...
}

@TableGenerator - 속성

image

allocationSize 의 경우 시퀀스 옵션과 동일하다고 보면 된다. 한 번에 50개를 DB테이블에 올려놓고 메모리에서 50개를 쓰는 방법이다. 웹 서버 열대가 동시에 호출하더라도 자기가 숫자를 확보하고 동작하기 때문에 문제는 없다. (동시성 문제X)

Note: 운영에선 Table 전략을 사용하기 부담스러움. 관례를 따르는 경우가 많음

권장하는 식별자 전략

  • 기본 키 제약 조건: null 아님, 유일, 변하면 안된다.
  • 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.
    • GenerateValue나 랜덤 값이나 비즈니스 value와 전혀 상관없는 값을 쓰는게 좋다.
  • 예를 들어 주민등록번호도 기본 키로 적절하기 않다.
  • 권장: Long형 + 대체키 + 키 생성전략 사용
  • 먼 미래를 보고 십몇억이 넘어도동작해야하기에 int형보다 Long형 타입을 사용하자.
This post is licensed under CC BY 4.0 by the author.

[에센셜 스크럼] Chapter7 - 추정 및 속도

[자바 ORM 표준 JPA 프로그래밍-기본편] 실전 예제1 - 요구사항 분석과 기본 매핑