Entity 매핑 #1
JPA를 사용하면서 가장 중요한 일이 java의 entity와 database의 table을 매핑하는 것이라고 해도 과언이 아니다. 따라서 우리는 매핑 어노테이션을 충분히 알고 써야할 책임이 있다. JPA는 4가지의 매핑 어노테이션을 지원한다.
- 객체와 테이블 매핑 : @Entity, @Table
- 기본 키 매핑 : @Id
- 필드와 컬럼 매핑 : @Column
- 연관관계 매핑 : @ManyToOne, @JoinColumn
@Entity
테이블과 엔티티를 매핑할 때에는 필수로 사용해야한다. @Entity 어노테이션에서 지원하는 속성은 다음과 같이 정리할 수 있다.
속성 | 기능 | default |
name | 엔티티 명 지정. 다른 패키지에 이름이 같은 엔티티 클래스가 있을 때 사용하여 충돌이 일어나지 않도록 한다. |
클래스 명 그대로 사용 |
이 어노테이션을 적용하기 위해서는 조건이 있다.
1. public 혹은 protected의 기본 생성자
2. enum, interface, inner 혹은 final class는 사용 불가
3. 필드에 final 사용 불가
@Table
엔티티와 매핑할 테이블을 지정한다. 지원하는 속성을 정리하면 다음과 같다.
속성 | 기능 | default |
name | 매핑할 테이블 이름 설정 | 엔티티 명 그대로 사용 |
catalog | catalog 기능이 있는 데이터베이스에서 catalog 매핑 | |
schema | schema 기능이 있는 데이터베이스에서 schema 매핑 | |
uniqueConstrains | DDL 생성 시에 유니크 제약조건 생성. |
상기 내용을 바탕으로 다음 java 코드를 살펴보자.
public enum RolrType {
ADMIN, USER
}
@Entity
@Table(name="MEMBER")
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME")
private String name;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Lob
private String description;
}
처음 나오는 어노테이션에 대해 알아보자. (속성에 대해서는 다음 시간에 다루겠다.)
- java의 enum으로 매핑하기 위해서는 @Enumerated를 사용하여야한다.
- database의 timestamp를 매핑하기 위해서는 @Temporal을 사용하여야한다.
- database의 clob을 매핑하기 위해서는 @Lob을 사용한다. blob 타입도 매핑할 수 있다.
※ 이름 매핑 전략
보통 java에서는 카멜 표기법을 사용하며 데이터베이스에서는 언더스코어를 사용한다. 그렇기 때문에 @Column의 name속성을 사용하여 매핑을 이루게 되는데 이러한 수고를 덜 수 있는 방법이 있다.
hibernate.ejb.naming_strategy 설정으로 org.hibernate.cfg.ImprovedNamingStrategy를 주면 된다.
해당 설정 값은 테이블 명이나 컬럼 명이 생략되면 자바의 카멜 표기법을 언더스코어 표기법으로 매핑하게 한다.
데이터베이스 스키마 자동생성
JPA는 데이터베이스 스키마를 자동으로 생성할 수 있도록 설정할 수 있다. 개인적인 생각이지만 매핑을 완벽하게 할 수 있어야 안전하게 사용할 수 있을거라고 생각한다.
JPA를 사용하기 위한 설정과 동작 원리에서 언급했던 것과 같이 spring.jpa.hibernate.ddl-auto 속성을 통해 자동생성을 지원한다. 자동생성되는 DDL은 데이터베이스 방언에 따라서 달라질 수 있다.
만약 이 기능을 사용하면 개발자가 직접 테이블을 만드는 시간을 절약할 수 있다. 그러나 개발 외에 운영 환경에서 사용할 만큼 완벽하지 않기 때문에 참고하는 정도로 사용하는 것으로 권장하고 있다.
DDL 자동생성에 대해 몇몇 제약조건이 따를 수 있다. 다음과 같이 java 코드를 살펴보자.
@Entity
@Table(name="MEMBER", uniqueConstraints = {@UniqueConstraint(name="NAME_AGE_UNIQUE", columnNames = {"NAME", "AGE"})})
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME", nullable = false, length = 10)
private String name;
@Enumerated(EnumType.STRING)
private RoleType roleType;
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;
@Lob
private String description;
}
JPA를 사용하기 위한 설정과 동작 원리에서 언급했지만 @Column에 대한 속성으로 제약조건을 줄 수 있다.
@Table의 uniqueConstraints 속성에 대해 알아보자. 상기 내용에 대해 생성된 DDL은 다음과 같다.
ALTER TABLE MEMBER
ADD CONSTRAINT NAME_AGE_UNUQUE
UNUQUE (NAME, AGE)
유니크 제약조건을 추가한 것이다. 이러한 속성은 DDL을 자동생성할 때 사용되며 JPA의 실행 로직에는 아무런 영향을 주지 않는다. 이 말은 DDL 자동생성을 사용하지 않는다면 이러한 속성도 사용할 필요도 없다는 이야기다. 그러나 코드만 보고도 테이블을 머릿 속에 그릴 수 있기 때문에 제약조건 등을 파악할 수 있는 좋은 점도 있다.