[JPA] 기본키(Primary Key) 매핑

김기현·2023년 1월 15일
0
post-thumbnail

@Id

데이터베이스 테이블의 기본 키(PK)와 객체의 필드를 매핑시켜주는 어노테이션이다.

적용가능한 타입
적용가능한 타입은 아래와 같다.

  • 자바 기본형
  • 자바 래퍼형
  • String
  • Date(java.util, java.sql)
  • BigDecimal
  • BigInteger

@Id만 사용할 경우 기본 키(PK)를 직접 할당해주어야 한다.
기본키를 직접 할당하는 대신 데이터베이스가 생성해주는 값을 사용하려면 @GeneratedValue를 사용하면 된다.

@Generated 어노테이션이 아님을 주의하자.

만약 @ID만 사용하면서 PK값을 직접 할당하지 않는 경우 아래의 에러가 발생한다.

[Error] ids for this class must be manually assigned before calling save()

nested exception is org.hibernate.id.IdentifierGenerationException: 
ids for this class must be manually assigned before calling save(): 
backend.core.domain.Staff

해당 에러의 발생 원인은 EntityManage.save() 함수를 호출하기 전에 id값이 설정되어 있어야 하는데, 그렇지 않아서이다.

@GeneratedValue

기본 키를 자동으로 생성해주는 어노테이션이다.

속성으로 strategy가 있으며 이를 통해 자동 생성 전략을 지정해줄 수 있다.

IDENTITY

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Facility {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "facility_id")
    private Long id;

    @OneToMany(mappedBy = "facility")
    private List<RoomFacility> roomFacilities;
}

@GeneratedValue(strategy = GenerationType.IDENTITY

IDENTITY전략은 기본 키 생성을 데이터베이스에 위임하는 전략이다.
주로 MySQL, PostgreSQL, SQL Server에서 사용한다.

데이터베이스의 AUTO_INCREMENT 기능을 통해 데이터베이스가 기본 키를 자동으로 생성해준다.
IDENTITY 전략은 AUTO_INCREMENT처럼 데이터베이스에 값을 저장하고 나서 기본 키 값을 구할 수 있을 때 사용한다.

주의점
엔티티가 영속 상태가 되기 위해선 식별자가 꼭 필요하다.

IDENTITY전략을 사용하면 식별자를 데이터베이스에서 지정하기 전까지 알 수 없기에 em.persist()를 하는 즉시 INSERT SQL이 데이터베이스에 전달된다.

즉 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.

SEQUENCE

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SequenceGenerator(
        name = "BOARD_SEQ_GENERATOR",
        sequenceName = "BOARD_SEQ",
        initialValue = 1,
        allocationSize = 1
)
public class Facility {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
        generator = "BOARD_SEQ_GENERATOR")
    @Column(name = "facility_id")
    private Long id;

    @OneToMany(mappedBy = "facility")
    private List<RoomFacility> roomFacilities;
}

@GeneratedValue(strategy = GenerationType.SEQUENCE
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 데이터베이스 오브젝트이다.

SEQUENCE 전략은 이 시퀀스를 사용해서 기본 키를 생성한다.

해당 전략은 오라클, PostgerSQL, H2 데이터베이스에서 사용할 수 있다.

시퀀스 전략을 사용하기 위해서 우선 사용할 데이터베이스 시퀀스를 매핑해야 한다.

@SequenceGenerator를 사용해 시퀀스 생성기를 등록한 후, @GeneratedValue의 generator 속성으로 시퀀스 생성기를 선택한다.

@SequenceGenerator 속성은 아래의 표와 같다.

IDENTITY와의 차이점

SEQUENCE 전략은 em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한다.
그리고 조회한 식별자를 엔티티에 할당한 후 해당 엔티티를 영속성 컨텍스트에 저장한다.
다음으로 트랜잭션 커밋 시점에 flush가 발생하면 엔티티를 데이터베이스에 저장한다.

IDENTITY `전략은 먼저 엔티티를 데이터베이스에 저장한 후에 식별자를 조회하여, 엔티티의 식별자에 할당 한다.
그 후 영속성 컨텍스트에 저장한다.

TABLE

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SequenceGenerator(
        name = "BOARD_SEQ_GENERATOR",
        table = "MY_SEQUENCE",
        sequenceName = "BOARD_SEQ",
        initialValue = 1,
        allocationSize = 1
)
public class Facility {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE,
        generator = "BOARD_SEQ_GENERATOR")
    @Column(name = "facility_id")
    private Long id;

    @OneToMany(mappedBy = "facility")
    private List<RoomFacility> roomFacilities;
}

SELECT * FROM MY_SEQUENCE를 하면 BOARD_SEQ 컬럽과 NEXT_VAL이 나타난다.

TABLE전략은 시퀀스 대신 테이블을 사용한다는 것 이외에 SEQUENCE전략과 동작하는 방식이 같다.

@TableGenerator 속성은 아래의 표와 같다.

AUTO

데이터베이스는 종류도 많고 데이터베이스의 종류에 따라 기본키를 만드는 방법도 다양하다.

AUTO로 설정하면 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다.

@GeneratedValue의 strategy의 기본값은 AUTO이다.

주의점
AUTO를 사용할 때 SEQUENCE, TABLE전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어야 한다.

만약 ddl-auto(스키마 자동 생성 기능)를 사용한다면, 하이버네이트가 기본값을 사용해서 적절하게 생성한다.

SEQUENCE , TABLE 전략의 최적화 방법도 존재한다.

profile
피자, 코드, 커피를 사랑하는 피코커

0개의 댓글