DEV ℧ Developer Diary

[JPA] 필드와 컬럼 매핑

해당 포스트는 인프런 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 듣고 정리한 글입니다.

필드와 컬럼 매핑

Entity와 테이블에 대해서는 비교적 간단했다면, JPA의 필드와 컬럼매핑의 경우 Enum 이나, 각종 컬렉션 객체에 대해 필드가 매핑되므로, 다양하다.

필드

아래의 예시를 통해 필드에 대해 설명을 해보자 한다.

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name="MEMBER")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
    @Id
    private Long id;

    @Column(name = "name")
    private String username;

    private Integer age;

    @Enumerated(EnumType.STRING)
    private RoleType roleType;

    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;

    @Lob
    private String description;
}

1.

@Id
private Long id;

테이블의 PK값을 나타냅니다.

2.

@Column(name = "name")
private String username;

필드명과 테이블의 컬럼명이 다를경우 @Column(name = "컬럼명") 을 사용하면, 테이블의 컬럼과 매칭이 가능하다.

3.

private Integer age;

원하는 필드명에 대해 타입을 지정할 경우 대게 원하는대로 컬럼 타입이 지정된다. ex) Integer를 사용할 경우 NUMBER 컬럼 타입이 지정된다.

4.

@Enumerated(EnumType.STRING)
private RoleType roleType;

DB 에는 Enum타입이 없다. Enum을 사용하기 위해서는 @Enumerated(EnumType.STRING)을 사용해야 한다.

5.

@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;

날짜타입을 쓰게된다면, @Temporal 을 사용하면 된다. DB의 타입은 DATE, TIME, TIMESTAMP타입을 사용하므로 구분을 주기위해 @Temporal의 속성에 타입을 정의해준다.

/* TemporalType의 enum */
public enum TemporalType {

    /** Map as <code>java.sql.Date</code> */
    DATE,

    /** Map as <code>java.sql.Time</code> */
    TIME,

    /** Map as <code>java.sql.Timestamp</code> */
    TIMESTAMP
}

6.

@Lob
private String description;

DB에 VARCHAR를 넘어서는 CLOB나 BLOB 같은 대용량 데이터의 경우 @Lob을 사용한다.

생성한 Entity를 JPA로 실행시 아래와 같은 CREATE문을 생성한다.

7.

@Transient
private int temp;

@Transient 어노테이션을 사용하면 필드를 실제 DB에 올리지않고 자바 메모리에서만 사용한다. (매핑 무시)

create table USER (
   id bigint not null,
    age integer,
    createdDate timestamp,
    description clob,
    lastModifiedDate timestamp,
    roleType varchar(255),
    name varchar(255),
    primary key (id)
)

@Column

@Column 안에 들어가는 속성으로 자주 사용하므로 잘 알아두는 것이 좋다.

  • name : 필드와 매핑할 테이블의 컬럼이름을 설정한다 (기본값 : 객체의 필드 이름)
  • insertable, updatable : 등록 및 변경 가능 여부를 설정한다. 해당 값을 설정할 경우 해당 필드에대한 INSERT 나 UPDATE 쿼리가 날라가지 않는다. (기본값 : true)
  • nullable : null 값의 허용 여부를 설정한다. false로 설정하면 DDL(CREATE) 생성시에 not null 제약 조건이 붙는다.
  • unique : @Table의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸때 사용한다. 하지만 잘 사용하지 않는다.

    제약 조건인 alter table TB_USER add constraint UK_nvlr3kdy2ky121gol63otka7p unique (name) 와 같이 랜덤하게 설정되어 로그를 알아보기 어렵다. 대용으로 @Table의 uniqueConstraints을 이용해 직접 이름을 설정하는 방식을 선호한다.

  • columnDefinition : 데이터베이스 컬럼 정보를 직접 줄 수 있음. ex) varchar(100) default ‘EMPTY’
  • length : 컬럼의 길이를 설정한다. String타입에만 사용 가능 (기본값 : 255)
  • precision, scale : BiDecimal나 BigInteger과 같은 큰 숫자타입을 사용할 때 사용, precision는 소수점을 포함한 전체 자릿수를 scale 은 소수의 자릿수 이다. double, float에는 적용되지 않는다. (기본값 : precision=19, scale=2)

@Enumerated

EnumType은 두가지 옵션이 있다.

  • EnumType.ORDINAL : enum 순서를 데이터베이스에 저장
  • EnumType.STRING : enum 이름을 데이터 베이스에 저장

Enum 타입을 필드로 사용할 때 주의 할 점이 있는데, @Enumerated 사용시 EnumType은 ORDINAL을 사용하면 안된다.

@Enumerated(EnumType.ORDINAL)
private RoleType roleType;

위와 같이 roleType 필드를 @Enumerated(EnumType.ORDINAL)을 준상태에서 User 엔티티를 DB에 넣어 주자. 공통적인 부분은 생략하고 아래와 같이 객체를 만들어 DB에 넣어주었다.

User user = new User();
user.setId(1L);
user.setUsername("만득이");
user.setRoleType(RoleType.USER);
entityManager.persist(user);

User user2 = new User();
user2.setId(2L);
user2.setUsername("천득이");
user2.setRoleType(RoleType.ADMIN);
entityManager.persist(user2);

JPA를 통해서 INSERT가 된 DB 결과 값을 보자

영속성 이점1

위의 사진과 같이 USER나 ADMIN으로 데이터값이 들어간 것이 아닌 0,1이 들어가있다. 이것은 해당 ENUM 타입의 INDEX값을 넣어준다. 이는 만약 RoleType의 제일 앞에 새로운 타입이 생길 경우 해당 값도 0으로 들어가 순서가 엉망으로 들어갈 수 있어 사용하는 것은 위험하다.

@Temporal

날짜 타입을 매핑할 때 사용한다. 아래와 같은 속성이있다.

TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑 (예 : 2022-06-15) TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑 (예 : 11:22:33) TemporalType.TIMESTAMP : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑 (예 : 2022-06-15 11:22:33)

하지만 최신 하이버네이트에서는 LocalDate(YYYYMM), LocalDateTime(YYYYMMDD)을 타입을 이용하면 해당 속성을 생략 할 수 있다.

@Lob

  • @Lob은 지정할 수 있는 속성이 없다.
  • 매핑하는 필드타입이 문자면 CLOB 매핑, 나머지는 BLOB를 매핑한다.
    • CLOB : String, char[], java.sql.CLOB
    • BOLB : byte[], java.sql.BLOB

@Transient

  • 필드를 매핑하지 않는다.
  • 캐싱이나, 메모리용 데이터를 저장할 때 사용한다.