엔티티 매핑

업데이트:

JPA를 사용하는데 가장 중요한 일은 엔티티와 테이블을 정확히 매핑하는 것이다. JPA는 다양한 매핑 어노테이션을 지원하는데 크게 4가지로 분류할 수 있다.

  • 객체와 테이블 매핑 : @Entity, @Table
  • 기본 키 매핑 : @Id
  • 필드와 컬럼 매핑 : @Column
  • @ManyToOne, @JoinColumn

@Entity

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

속성

  • name
    • JPA에서 사용할 엔티티 이름을 지정한다. 보통 기본값인 클래스 이름을 사용한다.
    • 만약 다른 패키지에 이름이 같은 엔티티 클래스가 있다면 이름 지정시 충될하지 않도록 해야 한다.

적용 주의사항

  • 기본 생성자 필수다.(파라미터가 없는 public, protected 생성자)
    • 자바는 생성자가 없으면 자동으로 만들지만 임이의 생성자가 있는 경우 직접 만들어 줘야 한다.
  • final 클래스, enum, interface inner 클래스는 사용할 수 없다.
  • 저장할 필드에 final을 사용하면 안된다.

@Table

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

속성

  • name : 매핑할 테이블 이름
  • catalog : catalog 기능이 있는 데이터베이스에서 catalog를 매핑한다.
  • schema : schema 기능이 있는 데이터 베이스에서 schema를 매핑한다.
  • uniqueConstraints : DDL 생성 시에 유니크 제약 조건을 만든다.

다양한 매핑 사용

@Enumerated

  • enum을 사용해서 데이터를 입력할때는 @Enumerated 어노테이션으로 매핑해야 한다.
  • 테이블에 데이터 저장시 enum값(0,1,2)와 변수명 값이 그대로 저장할 수 있는 방법이 있다.
  • enum 숫자값으로 저장하는 경우 필드 순서가 변경될경우 기존데이터와 값이 달라져 문제가 생길 수 있다.
  • 되도록이면 @Enurnerated (EnumType.STRING) 로 지정하여 변수값 그대로 저장해야 한다.

@Temporal

  • 자바의 날짜 타입은 @Temporal 사용해서 매핑한다.
  • 시분초가 있는지 없는지에 따라 @Temporal(TemporalType.TIMESTAMP), @Temporal(TemporalType.Date), @Temporal(TemporalType.Date) 구분해서 사용한다.
  • 자바8 이후에는 LocalDatetime, LocalDate가 나눠져 있어 따로 설정 없이 구분이 가능하다

@Lob

  • 설명하는 컬럼은 길이 제한이 없다. 따라서 데이터베이스 타입이 CLOB으로 지정해야 한다.
  • @Lob을 사용하면 CLOB,BLOB 타입을 매핑할 수 있다.

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

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

설정

  • persistence.xml에 <property name=”hibernate.hbm2ddl.auto” value=”“create”> 속성 추가
  • 속성을 추가하면 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다.
  • hibernate.show_sql 속성을 true로 설정하면 콘솔에 실행되는 테이블 생성 DDL을 출력할 수 있다.

스키마 자동 생성 기능을 사용하면 직접 테이블을 만드느 수고를 덜수는 있따 하지만 운영 환경에서 상요할 만큼 완벽하지 않아 매핑을 어떻게 해야 하는지 참고 정도로만 사용하는 것이 좋다.

속성

  • create : 기존 테이블을 삭제하고 생성한다. DROP + CREATE
  • create-drop : create속성에 애플리케이션을 종료할때 생성한 DDL을 제거한다. DROP + CREATE + DROP
  • update : 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다.
  • validate : 데이터베이스 테이블과 엔티티 매핑 정보를 비교해서 차이가 있으면 경고를 남기고 실행하지 않는다
  • none : 자동생성 기능을 사용하지 않으려면 속성 자체를 삭제하거나 유효하지 않는 값을 준다.(none은 유효하지 않은 값이다.)

DDL 생성 기능

  • 제약조건이 추가되었을떄 DDL에 이 제약조건을 추가할 수 있다.
@Entity
@Table(name="MEMBER")
public class Member{

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

    @Column(name="NAME", nullable=false, length=10)
    private String username;
}

이런 기능들은 단지 DDL을 자동으로 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.

기본 키 매핑

기본 키를 @Id 어노테이션을통해 애플리케이션에서 직접할당하는 데신 데이터베이스가 생성해주는 값을 사용할 수 있다. (오라클의 시퀀스 오브젝트,AUTO_INCREMENT 기능 등..)

기본 키 생성 전략

  • 직접 할당 : 기본 키를 애플리케이션에서 직접 할당
  • 자동 생성 : 대리 키 사용 방식
    • IDENTITY : 기본 키 생성을 데이터베이스에 위임한다.
    • SEQUENCE : 데이터베이스 시퀸스를 사용해서 기본 키를 할당한다.
    • TABLE : 키 생성 테이블을 사용한다.

자동 생성 전략이 다양한 이유는 데이터베이스 벤더마다 지원 하는 방식이 다르기 떄문이다.

기본 키 직접 할당 전략

  • @Id로 매핑하여 사용한다.
  • @Id 적용 가능 자바 타입
    • 자바 기본형
    • 자바 래퍼 형
    • String
    • java.util.Date
    • java.sql.Date
    • java.math.BigDecimal
    • java.math.BigInteger
  • em.persist()로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방법이다.
@Id
@Column(name="id")
private String id;

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

IDENTITY 전략

  • 기본 키 생성을 데이터베이스에 위임하는 전략이다.
    • 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용된다.
  • @GeneratedValue의 strategy 속성 값을 GenerationType.IDENTITY로 지정하면 된다.
  • 데이터 베이스에 값을 저장할때 ID 컬럼을 비워두면 각 데이트베이스별 기능에 맞게 순서대로 값을 채워준다.
    • ex) MySQL 컬럼에 AUTO_INCREMENT 설정되어 있으면 순서대로 채워진다.
  • 이 전략을 사용하면 JPA는 기본 키 값을 얻어오기 위해 데이터베이스를 추가로 조회한다.
@Entity
public class Board{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}

엔티티가 영속 상태가 되려면 반드시 식별자가 필요하다. IDENTITY 식별자 생성 전략은 데이터베이스에 저장해야 구할 수 있으므로 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달되고 쓰기 지연이 동작하지 않는다.

SEQUENCE 전략

  • 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터 오브젝트이다.
    • 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.
  • 사용 코드는 IDENTITY 전략과 같지만 내부 동작 방식은 다르다.
    1. em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한다.
    2. 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.
    3. 이후 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 데이터베이스에 저장한다.
  • @SequenceGenertor 속성
    • name : 식별자 생성기 이름
    • sequenceName : 데이터베이스에 동록되어 있는 시퀀스 이름
    • initialValue : DDL 생성시에만 사용됨, DDL을 생설할떄 처음 시작하는 수를 지정
    • allocationSize : 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨)
    • catalog, schema : 데이터베이스 catalog, schema 이름
@Entity
@SequenceGenerator(
    name = "BOARD_SEQ_GENERATOR",
    sequenceName = "BOARD_SEQ", // 매핑할 데이터베이스 시퀀스 이름    
    initialValue = 1, allocationSize = 1)
public class Board {
    
    @Id
    @GeneratedValue(strategy = "BOARD_SEQ_GENERATOR")
    private Long id;
}

allocationSize는 지정한 수만큼 시퀀스를 증가 시키고 메모리에 식별자를 할당한다. 그리고 지정한 수가 넘어가면 다시 지정한 수만큼 증가시킨다음 메모리에 식별한다.
이 방식을 사용하면 여러 JVM이 동시에 동작해도 기본 키 값이 충돌되지 않는 장점이 있다. 반면에 데이터베이스에 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가한다는 점을 염두해 둬야 한다.

TABLE 전략

  • 먼저 키생성 용도로 테이블을 만들어 사용하는 방식이다.
  • 테이블을 따로 만들어 사용하기 때문에 어떠한 DB를 사용하더라고 적용이 가능하다.
  • 테이블 생성시 sequence_name 컬럼을 시퀀스 이름으로 사용하고 next_val 컬럼을 시퀀스 값으로 사용한다.
import org.springframework.boot.autoconfigure.domain.EntityScan;

@Entity
@TableGenerator(
        name="BOARD_SEQ_GENERATOR",
        table="MY_SEQUENCES",
        pkColumnValue="BOARD_SEQ", allocationSIze=1
)

태그:

카테고리:

업데이트:

댓글남기기