본문 바로가기

CS/자바 ORM 표준 JPA 프로그래밍

[JPA] 엔티티 매핑

해당 포스트는 김영한 님의 [자바 ORM 표준 JPA 프로그래밍] 을 읽고 정리한 글입니다.

 

1. @Entity

JPA 사용해서 테이블과 매핑할 클래스는 @Entity 어노테이션을 필수로 붙여야 한다. 어노테이션이 붙은 클래스는 JPA 관리하는 것으로, 엔티티라 부른다.

 

## 주의사항

  • 기본 생성자는 필수다
    • JPA 엔티티 객체를 생성할 기본 생성자를 사용하기 때문
  • Final 클래스, enum, interface, inner 클래스에는 사용할 없다
  • 저장할 필드에 final 사용하면 안된다

 

 


2. @Table

엔티티와 매핑할 테이블을 지정한다. 생략하면 매핑한 엔티티 이름을 테이블 이름으로 사용한다.

 


3. 데이터베이스 스키마 자동 생성

JPA 데이터베이스 스키마를 자동으로 생성하는 기능을 지원한다. 클래스의 매핑정보를 보면 어떤 테이블에 어떤 컬럼을 사용하는지 있다. JPA 매핑정보와 데이터베이스 방언을 사용해서 데이터베이스 스키마를 생성한다.

 

스키마 자동 생성 기능을 사용하면 애플리케이션 실행 시점에 데이터베이스 테이블이 자동으로 생성되어 개발자가 테이블을 직접 생성하는 수고를 있다. 물론 스키마 자동 생성 기능이 만든 DDL 운영 환경에서 사용할 만큼 완벽하지는 않다.

 

 

## Hibernate.hbm2ddl.auto 속성

1. Create

2. Create-drop

3. Update

4. Validate

5. None


4. 기본 키 매핑

@Id 어노테이션만 사용해서 기본 키를 애플리케이션에서 직접 할당하는 대신에 데이터베이스가 생성해주는 값을 사용하려면 어떻게 매핑해야 할까? 데이터베이스마다 기본 키를 생성하는 방식이 서로 달라 문제를 해결하기는 쉽지 않다.

그렇기에 JPA는 다양한 전략을 제공하여 해결한다.

 

기본 키 생성 전략에는 크게 직접 할당과 자동 생성, 두 가지로 나눌 수 있다.

 

1. 직접 할당: 기본 키를 애플리케이션에서 직접 할당

2. 자동 생성: 대리 키 사용 방식

  • IDENTITY: 기본 생성을 데이터베이스에 위임
  • SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키를 할당
  • TABLE: 생성 테이블을 사용
자동 생성 전략이 다양한 이유

데이터베이스 벤더마다 지원하는 방식이 다르기 때문이다. 기본 키를 직접 할당하려면 @Id 사용하면 되고, 자동 생성 전략을 사용하려면 @Id @GeneratedValue 추가하고 원하는 생성 전략을 선택하면 된다.

 

 

 

1) 기본 키 직접 할당 전략

@Id
@Column(name = "id")
private String id;

기본 키를 직접 할당하려면 다음 코드와 같이 @Id로 매핑하면 된다.

 

 

기본 키 직접 할당 전략은 em.persist()로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방법이다.

Board board = new Board();
board.setId("id1"); // 기본 키 직접 할당
em.persist(board);

 

참고
기본 키 직접 할당 전략에서 식별자 값 없이 저장하면 예외가 발생한다.
하이버네이트를 구현체로 사용하면 JPA 최상위 예외인 javax.persistence.PersistenceException 예외가 발생하는데, 내부에 하이버네이트 예외인 org.hibernate.id.IdentifierGenerationException 예외를 포함하고 있다.

 

 

 

 

2) IDENTITY 전략

IDENTITY 기본 생성을 데이터베이스에 위임하는 전략이다. IDENTITY 전략은 데이터베이스에 값을 지정하고 나서야 기본 값을 구할 있을 사용한다.

주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다.

 

개발자가 엔티티에 직접 식별자를 할당하면 @Id 어노테이션만 있으면 되지만 식별자가 생성되는 경우에는 @GeneratedValue 어노테이션을 사용하고 식별자 생성 전략을 선택해야 한다.

@Entity
public class Board {

    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    ...   
}
  • IDENTITY 전략을 사용하려면 위 코드와 같이 @GeneratedValue의 strategy 속성 값을 IDENTITY로 지정한다. 이 전략을 사용하면 JPA는 기본 키 값을 얻어오기 위해 데이터베이스를 추가로 조회한다.

 

 

주의
엔티티가 영속 상태가 되려면 식별자가 반드시 필요하다. 그런데 IDENTITY 식별자 생성 전략은 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있어 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다. 따라서 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.

 

 

 

 

3) SEQUENCE 전략

이 전략은 유일한 값을 순서대로 생성하는 시퀀스를 사용하여 기본 키를 생성한다. 

이 전략은 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2a 데이터베이스에서 사용할 수 있다.

 

@Entity
@SequenceGenerator(
    name = "BOARD_SEQ_GENERATOR", 
    sequenceName = "BOARD_SEQ", // 매핑할 데이터베이스 시퀀스 이름
    initialValue = 1, allocationSize = 1)
public class Board {

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

위 코드처럼 우선 사용할 데이터베이스 시퀀스를 매핑한다.

  • 예제에서는 @SequenceGenerator를 사용해서 BOARD_SEQ_GENERATOR라는 시퀀스 생성기를 등록하고 sequenceName 속성의 이름으로 BOARD_SEQ를 지정한다. 그러면 JPA는 이 시퀀스 생성기를 실제 데이터베이스의 BOARD_SEQ 시퀀스와 매핑한다.
  • 다음으로 generator = "BOARD_SEQ_GENERATOR"로 방금 등록한 시퀀스 생성기를 선택하면 id 식별자 값에 해당 시퀀스 생성기가 할당한다.

 

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

 

반대로 IDENTITY 전략은 먼저 엔티티를 데이터베이스에 저장한 후에 식별자를 조회해서 엔티티를 식별자에 할당한다.

 

 

 

 

4) TABLE 전략

이 전략은 키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략이다. 전략은 테이블을 사용하므로 모든 데이터베이스에 적용할 있다.

 

@Entity
@TableGenerator(
    name = "BOARD_SEQ_GENERATOR", 
    table = "MY_SEQUENCES",
    pkColumnValue = "BOARD_SEQ", allocationSize = 1)
public class Board {

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

 

  • @TableGenerator를 사용해서 테이블 키 생성기를 등록한다. BOARD_SEQ_GENERATOR라는 테이블 키 생성기를 등록하고 MY_SEQUENCES 테이블을 키 생성용 테이블로 매핑한 후, GenerationType.TABLE을 선택하면 TABLE 전략을 사용하게 된다.
  • 그리고 @GeneratedValue.generator에 방금 만든 테이블 키 생성기를 지정하면 id 식별자 값은 BOARD_SEQ_GENERATOR 테이블 키 생성기가 할당한다.

 

해당 전략은 시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작 방식이 같다.

 

 

 

 

5) AUTO 전략

데이터베이스의 종류도 많고 기본 키를 만드는 방법도 다양하다. 이때 GenerationType.AUTO 선택한 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 하나를 자동으로 선택한다.

 

 

@Entity
public class Board {

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

 

AUTO 전략은 데이터베이스를 변경해도 코드를 수정할 필요가 없다는 장점이 있다.

AUTO를 사용할 때 SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다. 만약 스키마 자동 생성 기능을 사용하면 하이버네이트가 기본값을 사용해서 적절한 시퀀스나 키 생성용 테이블을 만든다.

'CS > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글

[JPA] 프록시와 연관관계 관리  (0) 2024.01.08
[JPA] 연관관계 매핑  (1) 2024.01.07
[JPA] 영속성 관리  (1) 2023.10.31
[JPA] JPA 소개  (0) 2023.10.29