쌍문동 척척박사
Spring / ReactJS / PS

엔티티 매핑

엔티티 매핑

JPA에서 가장 중요한 요소, 영속성 컨텍스트에 이어 두 번째 요소인 객체-RDB 매핑 (ORM)에 대해 소개하겠다. ORM은 크게 엔티티 매핑과 연관관계 매핑이 있는데, 이번 포스트에서는 엔티티 매핑에 대해 다루려 한다.

관련 포스트 : 연관관계 매핑


객체와 테이블 매핑

여기서 말하는 객체는 엔티티 (Entity)를 말한다. 우리의 목표는 DB에서 설계한 테이블엔티티 형태로 가져와 객체지향적으로 다루는 것이다. 엔티티 생성은 어렵지 않다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Getter
@NoArgsConstructor
@Entity
public class Item {

    @Id @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;
    private int stockQuantity;

    @Builder
    public Item(String name, int price, int stockQuantity){
        this.name = name;
        this.price = price;
        this.stockQuantity = stockQuantity;
    }
}

2.png

lombok 어노테이션이 섞여 있어 조금 헷갈릴 수 있지만, 확실한 건 @Entity 어노테이션이 클래스를 JPA가 관리하는 엔티티로 만든다는 것이다.

@Entity

  • 엔티티의 클래스명은 테이블 매핑 시 기본적으로 Camel Case에서 Snake Case로 변경된 이름의 테이블에 자동 매핑된다.
    • ex) class OrderItem -> order_item
  • 엔티티는 기본 생성자를 필수로 선언해야 한다.
    • 자바는 기본생성자 부재 시 기본 생성자를 자동 생성한다.
    • 자바는 파라미터가 있는 생성자가 있으면 기본 생성자를 자동 생성하지 않는다.
  • final, enum, interface, inner 클래스는 엔티티로 사용할 수 없다.

@Table

1
2
3
4
5
6
7
8
9
// user_item 테이블에 매핑됨
@Table(name = "user_item", uniqueConstraints = {@UniqueConstraint(
  name = "name_age_unique", // 제약 조건명 (생략 가능)
  columnNames = {"name", "age"} // unique 조건 대상 컬럼명
)})
@Entity
public class Item {
    // ...
}
  • name : 매핑할 DB 테이블을 지정함
  • catalog / schema : DB catalog와 schema에 매핑함
  • uniqueConstraints : DDL 생성 시 유니크 제약 조건을 선언함

필드와 컬럼 매핑

객체 내 필드는 자동 생성된 Snake Case 형태의 테이블 컬럼으로 매핑된다. 하지만 @Column 어노테이션을 사용하면 몇 가지 제약 조건을 명세할 수 있다.

@Column

1
2
3
4
5
@Column(name="user_name", updatable=false, length=50)
private String name;

@Column(columnDefinition="varchar(50) default EMPTY")
private String major;
  • name : 필드와 매핑할 테이블 컬럼 이름
  • insertable / updatable : 등록 / 변경 가능 여부
  • nullabe : Null 여부 (기본값 true)
  • unique : 보통 @Table(uniqueConstraints=”…”)로 대체
  • columnDefinition : 컬럼 정보를 문자열 형태로 직접 선언함
  • length : 문자열 길이 (기본값 255)
  • precision / scale : BigDecimal / BigInteger 타입을 다룰 때 사용

@Enumerated

1
2
3
public enum RoleType {
    USER, ADMIN
}
1
2
@Enumerated(EnumType.STRING)
private RoleType roleType;
  • 자바의 enum 타입을 사용한다. (DB에는 enum 타입이 없음)
  • ORDINAL : 속성 명시 안할 시 기본값. 사용하지 않을 것을 권고함
  • STRING : VARCHAR 형태로 컬럼에 매핑됨

@Lob

1
2
@Lob
private String description;
  • BLOG, CLOB에 매핑함
    • 필드 타입 문자 -> CLOB 매핑
    • 필드 타입 나머지 -> BLOB에 매핑 (ex byte[] -> BLOB)
  • VARCHAR 이상의 데이터를 다룰 때 사용함

@Transient

1
2
@Transient
private int sum;
  • DB에 매핑하지 않고 메모리에서만 사용하는 필드를 지정함
  • 임시로 값을 보관할 때 사용

기본키 매핑

기본키는 @Id 어노테이션으로 지정하며, 기본키의 값은 직접 지정할 수도 있지만 DB가 자동으로 생성해주는 값을 사용하는 경우가 더 많다. DB마다 기본키를 생성하는 방식이 다르기 때문에 JPA에는 @GeneratedValue 어노테이션과 함께 여러 값 생성 전략을 사용해 값을 생성한다.

1. IDENTITY 전략

1
2
3
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
  • DB에 기본키 생성을 위임한다. (ex MairaDB : AUTO_INCREMENT)
  • JPA는 트랜잭션 커밋 시점에 INSERT SQL을 시행하기 때문에 DB에 실제로 컬러밍 생성되기 전에는 ID값을 알 수 없다.
  • 따라서 JPA에서는 IDENTITY 전략 사용 시 em.persist() 시점에 즉시 SQL을 실행해 PK 를 바로 알아낸다.
  • 쿼리 실행 후 받아온 PK 값은 1차 캐시에 저장된다.

2. SEQUENCE 전략

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
@SequenceGenerator(
        name="ITEM_SEQ_GENERATOR",
        sequenceName="ITEM_SEQ",    // 매핑할 DB 시퀀스명
        initialValue = 1,
        allocationSize = 1  // Default : 50
)
public class Item{
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
            generator = "ITEM_SEQ_GENERATOR")
    private Long id;
}
  • 시퀀스는 유일한 값을 순서대로 생성하는 특별한 DB 오브젝트다. (ex 오라클 시퀀스)
  • 오라클, PostgreSQL, H2 DB 등에서 사용된다.

3. TABLE 전략

  • 성능으로 인해 권장되지 않는 전략이다.

4. AUTO 전략

1
2
3
@Id
@GeneratedValue
private Long id;
  • JPA 구현체에 따라 자동으로 위 3개 생성 전략 중 하나를 선택한다.
  • 속성 미 선언 시 기본값으로 지정된다.

DB 스키마 자동 생성 (DDL)

모든 매핑은 DB에 해당 테이블이 존재한다는 가정 하에 동작한다. JPA에는 사용자가 테스트 시 매번 테이블을 생성할 필요 없도록, DB 스키마를 자동으로 생성하는 기능을 제공한다.

3.png

1
2
3
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>

persistence.xml에 스키마 자동 생성 옵션을 설정하면 어플리케이션 실행 시점에 선언한 엔티티에 대한 DDL이 자동 생성되어 수행된다.

hibernate.hbm2ddl.auto

  • create : 기존 테이블 삭제 후 다시 생성함
  • create-drop : create 시행 후 종료 시점에 테이블 DROP
  • none : 자동 생성 옵션을 사용하지 않음

주의

  • 자동 생성된 DDL은 실제 운영 환경에서 사용할만큼 완벽하진 않기에 참고용으로만 사용한다.
  • 운영 서버에서는 절대 DDL 자동 생성 기능을 사용하면 안된다. 개발 서버에서만 테스트용으로 사용한다.

참고 자료

자바 ORM 표준 JPA 프로그래밍

comments powered by Disqus