본문 바로가기
JAVA

[JPA] 엔티티 매핑 - 기본 키 매핑

by 고 민 2024. 1. 6.
728x90
반응형

 

Entity와 DB의 기본 키 매핑 방식과 전략에 대해 알아보자. 

@Id

엔티티의 해당 필드가 기본 키임을 알려주는 어노테이션.

@GeneratedValue 

기본 키 생성 방법을 명시할 수 있는 어노테이션. GeneratedValue를 사용할 경우 JPA가 id가 null값인 것을 확인한 후 전략을 전략을 실행하기 때문에 객체 생성 시 개별적으로 ID를 부여하면 작동하지 않으니 주의하자. 

GenerationType

@GeneratedValue의 전략을 명시하는 속성값. 아래와 같이 4가지 속성이 있다. 

  • AUTO
  • IDENTITY
  • SEQUENCE
  • TABLE 

IDENTITIY 

기본 키 생성을 DB에 위임한다.

JPA는 일반적으로 영속성 콘텍스트 등록 후 COMMIT 시 SQL이 실행되지만, 영속성 부여 시에 insert SQL을 즉시 실행한다. JDBC 드라이버 내부적으로 INSERT 했을 때 값을 리턴 받는 로직이 짜여있어 SELECT 문을 날리지 않아도 내부적으로 insert시점에 pk값을 가지고 와서 JPA가 영속성 컨텍스의 PK값으로 사용한다. 

예) MySql의 AUTO_INCREAMENT 옵션

위와 같은 이유로 IDENTITY 전략에서는 COMMIT 시점에 쓰기 저장소에 있는 SQL을 버퍼링 해서 밀어 넣는 게 불가능하지만 실무에서 성능에서 큰 매리트를 가지진 않는다. ( 한 트랜잭션 안에서 DB와 여러 번 연결되기 때문) 

흐름을 정리하자면 아래와 같다. 

영속성 부여  퓨시점(persist('object')) -> INSERT SQL -> PK 조회 -> COMMIT 

 

Sequence 

Sequence를 생성해 영속성 컨텍스트 시점에 pk로 사용한다. 

Member.class 

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

 

별도 옵션을 지정하지 않으면 hibernate가 임의로 시퀀스명을 부여해서 생성.

start with 1 inrement by 1  : 1번부터 1개씩 생성하겠다는 의미. 

Hibernate: create sequence hibernate_sequence start with 1 increment by 1

==================================
Hibernate: 
    
    create table Member (
       id bigint not null,
        RoleType varchar(255),
        description clob,
        fileSize blob,
        name varchar(100) default 'EMPTY',
        primary key (id)
    )

 

 

흐름 : 시퀀스 생성 -> 테이블생성 -> 시퀀스 번호 호출 -> 영속성 컨텍스트 저장 -> SQL 쓰기 영역 보관 -> COMMIT시 SQL 일괄 처리 

 

@SequenceGenerator

시퀀스 제너레이터를 이용하면 시퀀스 전략의 제너레이터 네임과 매핑하여 생성시 시퀀스 이름 및 생성 범위를 지정 할 수 있다. 

name : generator 이름.

sequenceName : 생성될 시퀀스명.

initialValue : 시퀀스 시작 번호.

allocationSize : DB 시퀀스의 값을 미리 할당하는 방식으로 성능 최적화를 위해 사용된다. 

@SequenceGenerator(
	name = MEMBER_SEQ_GENERATOR,  	// 제너레이터 이름 
    sequenceName = "MEBER_SEQ",		// 시퀀스 이름 
    initialVAlue = 1, allocationSize = 50 // 생성 범위 
)
public class Member(){
	/** ..생략.. **/
    
    @Id
    @GeneratedValue(staratege = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR")  
    private Long id 

}

 

allocation size를 50으로 설정하면 시퀀스를 미리 50개 생성해 메모리에 할당하고 51개가 모두 할당되면 DB에 접근해 50개를 다시 생성하고 메모리에 할당하는 식으로 동작한다.  DB에 접근하지 않고도 시퀀스 값을 순차 적으로 증가시킬 수 있어 DB에 시퀀스 호출을 위해 커넥션을 맺을 필요가 없어지기 때문에 성능 이점이 있고 동시성 문제에서 자

@Table

key 생성 전용 테이블을 만들어 데이터베이스 시퀀스를 흉내 내는 전략.

테이블 하나를 만들어서 key를 계속 뽑는다. 

모든 DB에 사용 가능하지만 Squence에서 가능한 최적화가 안되기 때문에 성능이 떨어진다. 

@TableGenerator 

@TableGenerator(
	name = "MEMBER_SEQ_GENERATOR",
    table = "MY_SEQUENCES",
    pkColumnValue = "MEMBER_SEQ", allocationSize = 1 )

@Auto 

방언에 따라 아래 전략 3가지 중 1개가 자동으로 선택되며, 기본값으로 설정된다. 

 

권장하는 식별자 전략

Long + 대체키 + 키 생성 전략 사용을 권장한다. 

시퀀스 이용 시  10억개 정도 생성되면 다시 0으로 초기화되기 때문에 되도록 Long을 사용한다. 

기본 키 제약 조건 : null 아님, 유일 식별자, 변하면 안 됨

 

위 3가지 중 '변하면 안됨' 조건을 만족시키기 가장 어렵다. 

기본키 전략을 만족하는 자연키는 찾기 어렵기 때문.

따라서 대체키 사용이 권장된다.

 

예를 들어 회원 테이블에서 주민번호를 기본 키로 사용한다고 해보자

개인정보 보호 정책 변화로 주민등록 번호를 더 이상 사용하지 못하게 되면 회원 테이블과 조인하는 다른 모든 테이블에 회원 정보를 참조하는 FK도 전부 마이그레이션 하는 상황이 발생한다. 

되도록 변경될 일이 없는 대체키를 사용하자. 

728x90
반응형