본문 바로가기
Spring/JPA

Entity-Table 매핑 - 기본키 매핑

by YellowCow 2023. 2. 24.

JPA에서 기본키를 어떻게 매핑할 수 있는지 알아보겠다

 

먼저, 엔티티에서 기본키를 매핑하려면

기본키에 해당하는 필드 위에 @Id 애너테이션을 붙이면 된다

@Entity
public class Member{
    @Id
    public Long id;
}


그리고 기본키 타입이 정수형일 경우

Insert시 기본키 값이 자동으로 증가되게 하려면

@GeneratedValue라는 애너테이션을 기본키에 해당하는 필드 위에 붙이면 된다

@Entity
public class Member{
    @Id
    @GerneratedValue(strategy=GenerationType.AUTO)
    public Long id;
}

 

@GeneratedValue에는 기본키값을 증가시키는 여러 전략들이 존재한다

 

@GeneratedValue 전략

  • GenerationType.AUTO - DBMS의 방언에 따라 설정(기본값)
@Entity
public class Member{
    @Id
    @GerneratedValue(strategy=GenerationType.AUTO)
    public Long id;
}

 

  • GenerationType.TABLE - 기본키값을 관리하는 테이블을 만들어서 기본키값을 가져옴, @TableGenerator필요, 모든 DBMS에 적용가능
/* JPA에서 생성해주는 기본 Sequence 테이블을 이용 */
// 다른 테이블과 Sequence 테이블을 혼용할 수 있으니 주의
@Entity
public class Member{
    @Id
    @GerneratedValue(strategy=GenerationType.TABLE)
    public Long id;
}

/* 직접 생성한 Sequence 테이블을 이용 */
@Entity
@TableGenerator(
        name="MEMBER_SEQ_GENERATOR",	//TableGenerator명
        table = "MEMBER_SEQS",		//시퀀스 테이블명
        pkColumnName = "MEMBER_SEQ",	//시퀀스 컬럼명
        initialValue = 1,		//시작값
        allocationSize = 50		//매 호출 시마다 가져올 시퀀스 값의 크기
)
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "MEMBER_SEQ_GENERATOR")
    private Long Id;
}

GenerationType.TABLE의 경우에는 DBMS에서 제공해주는 Sequence나 AUTO_INCREMENT보다 성능이 좋지 않으므로 비추

-> 아래를 보면 기본키를 가져오는 쿼리 외에도 다음 값으로 증가시키는 Update 쿼리가 날라가는 걸 볼 수 있다
     (성능저하의 원인)

시퀀스 테이블에 Lock이 걸릴 수 있다(Update 시)

/* 기본키값을 가져오는 쿼리 */
Hibernate: 
    select
        tbl.next_val 
    from
        MEMBER_SEQS tbl 
    where
        tbl.MEMBER_SEQ=? for update
            
/* 다음 기본키값으로 업데이트 하는 쿼리 */
Hibernate: 
    update
        MEMBER_SEQS 
    set
        next_val=?  
    where
        next_val=? 
        and MEMBER_SEQ=?
        
/* 가져온 기본키값으로 데이터를 Insert하는 쿼리 */        
Hibernate: 
    /* insert org.example.domain.Member
        */ insert 
        into
            Member
            (age, gender, name, Id) 
        values
            (?, ?, ?, ?)

 

  • GenerationType.SEQUENCE - 오라클용, 시퀀스를 이용하여 기본키값을 가져옴, @SequenceGenerator 필요
/* JPA에서 생성해주는 시퀀스 사용 */
//다른 테이블과 시퀀스를 같이 쓰게 될 수도 있으니 주의
@Entity
public class Member{
    @Id
    @GerneratedValue(strategy=GenerationType.SEQUENCE)
    public Long id;
}


/* 직접 생성한 시퀀스 사용 */
@Entity
@SequenceGenerator(
    name="MEMBER_SEQ_GENERATOR",	//SequenceGenerator 이름
    sequenceName = "MEMBER_SEQ",	//시퀀스 이름
    initialValue = 1,			//시퀀스 시작값
    allocationSize = 1  		//매 호출 시마다 가져올 시퀀스 값의 크기
)
public class Member{
    @Id
    @GeneratedValue(
    	strategy = GenerationType.SEQUENCE,	//GeneratedValue 전략
        generator = "MEMBER_SEQ_GENERATOR"	//사용할 SequenceGenerator 이름
    )
    public Long id;
}

 

  • GenerationType.IDENTITY - MySQL용, AUTO_INCREMENT를 이용하여 기본키값을 가져옴
@Entity
public class Member{
    @Id
    @GerneratedValue(strategy=GenerationType.INDENTITY)
    public Long id;
}

IDENTITY(AUTO_INCREMENT) 전략의 경우, PK값을 데이터를 Insert 하기 전까지 알 수 없다

(데이터를 Insert 할 때 PK값이 결정되기 때문이다)

그래서, JPA 내부적으로 영속성 컨텍스트에 PK값을 저장하기 위해

Insert 후 PK값을 Select하여 가져온다

 

위와 같은 이유로 IDENTITY 전략에서는 쿼리를 모아서 보낼 수 없다

persist 실행 후 바로 Insert 쿼리가 날라간다

댓글