////
Search
Duplicate
🏔️

4장. 엔티티 매핑

JPA를 사용함에 있어서 가장 중요한 일은 엔티티와 테이블을 정확히 매핑하는 것이다. 따라서 매핑 어노테이션을 숙지하고 사용해야 한다.
JPA는 다양한 매핑 어노테이션을 지원하며 크게 4가지로 분류할 수 있다.
객체와 테이블 매핑: @Entity, @Table
PK 매핑: @Id
필드와 컬럼 매핑: @Column
연관관계 매핑: @ManyToOne, @JoinColumn

1. @Entity

@Entity가 붙은 클래스는 JPA가 관리하는 것으로 엔티티라 부른다.
속성은 다음과 같다.
name: JPA에서 사용할 엔티티 이름을 지정한다. 기본값은 클래스 명이다.
@Entity 적용 시 주의사항은 다음과 같다.
기본 생성자는 필수다.(매개변수가 없는 public 또는 protected 생성자)
final 클래스, enum, interface, inner 클래스에는 사용할 수 없다.
저장할 필드에 final을 사용하면 안 된다.
JPA가 엔티티 객체를 생성할 때, 기본 생성자를 사용하므로 이 생성자는 바드시 있어야 한다.
생성자가 없는 경우, 기본 생성자를 만드나 생성자가 하나라도 없는 경우, 기본 생성자를 만들어주어야 한다.

2. @Table

@Table은 엔티티와 매핑할 테이블을 지정한다. 생략하면 매핑한 엔티티 이름을 기본값으로 사용한다.
속성은 다음과 같다.
name: 매핑할 테이블 명으로, 기본값은 테이블명이다.
catalog: catalog 기능이 있는 데이터베이스에서 catalog를 매핑한다.
schema: schema 기능이 있는 데이터베이스에서 schema를 매핑한다.
uniqueConstraints: DDL 생성 시, 유니크 제약조건을 만든다. 2개 이상의 복합 유니크 제약조건도 만들 수 있다.
단, 자동 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용된다.

3. 다양한 매핑 사용

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

JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원한다.
JPA는 클래스의 매핑 정보와 데이터베이스 방언을 사용해서 데이터베이스 스키마를 생성한다.
hibernate.hdm2ddl.auto의 값을 create로 바꾸면 어플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다.
create: 기존 테이블을 삭제하고 새로 생성한다.
create-drop: create 속성에 추가로 어플리케이션을 종료할 때 생성한 DDL을 제거한다.
update: 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다.
validate: 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 어플리케이션을 실행하지 않는다.
운영서버에서 DDL을 수정하는 옵션은 절대 사용해선 안 된다. 개발 서버나 개발 단계에서만 사용해야 한다.
개발 초기 단계는 create, update
초기화 상태로 자동화된 테스트를 진행하는 개발자 환경과 CI 서버는 create, 또는 create-drop
테스트 서버는 update 또는 validate
스테이징과 운영 서버는 validate

5. DDL 생성 기능

스키마 자동 생성 기능을 통해 만들어지는 DDL에 어노테이션들을 활용해 제약조건을 추가할 수 있다.
@Column, @Table의 속성을 적절히 사용하면 된다.

6. 기본 키 매핑

기존에는 @Id 어노테이션만 사용해서 회원의 기본 키를 어플리케이션에서 직접 할당했다.
기본 키를 어플리케이션에서 직접 할당하는 대신, 데이터베이스가 생성해주는 값을 사용하려면 어떻게 매핑해야할까?
오라클의 시퀀스 오브젝트, MySQL의 AUTO_INCREMENT같은 기능을 사용해 생성된 값을 기본 키로 사용하는 것 말이다.
이처럼 데이터베이스마다 기본 키를 생성하는 방식이 다르므로 이 문제를 JPA는 어떻게 해결할까?
JPA가 제공하는 데이터베이스 키 생성 전략은 다음과 같다.
직접 할당: 기본 키를 어플리케이션에서 직접 할당한다.
자동 생성: 대리키 사용 방식
IDENTITY: 기본 키 생성을 데이터베이스에 위임한다.
SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키를 할당한다.
TABLE: 키 생성 테이블을 사용한다.
기본 키를 직접 할당하려면 @Id를 사용하면 되고 자동 생성 전략을 사용하려면 @GeneratedValue 속성을 이용해 원하는 키 생성 전략을 선택하면 된다.

1. 기본 키 직접 할당 전략

기본 키를 직접 할당하려면 속성을 @Id로 매핑하면 된다. 적용 가능한 자바 타입은 다음과 같다.
자바 기본형, 자바 래퍼형, String, java.util.Date, java.sql.Date, java.math.BigDecimal, java.math.BigInteger
기본 키 직접 할당 전략은 em.persist()로 엔티티를 저장하기 전에 어플리케이션에서 기본 키를 직접 할당하는 방법이다.

2. IDENTITY 전략

기본 키 생성 전략을 데이터베이스에 위임하는 전략으로 데이터베이스에 영속성 객체를 저장할 때, 기본 키 속성을 비워두면 데이터베이스가 값을 채워준다.
@GenerateValue 어노테이션을 사용하고 식별자 생성 전략을 GenerationType.TypeIDENTITY로 지정하면 된다.

3. SEQUENCE 전략

데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트로 SEQUENCE 전략은 이 시퀀스를 사용해서 기본 키를 생성한다.
이 전략은 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다.

4. TABLE 전략

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

5. AUTO 전략

AUTO는 선택한 데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다.
데이터베이스를 변경해도 코드를 수정할 필요가 없으므로 특히 키 생성 전략이 아직 확정되지 않은개발 초기 단계나 프로토타입 개발 시 편리하게 사용할 수 있다.

6. 기본 키 매핑 정리

영속성 컨텍스트는 엔티티를 식별자 값으로 구분하므로 엔티티를 영속 상태로 만들려면 식별자 값이 반드시 있어야 한다.
em.persist()를 호출한 직후 발생하는 일을 식별자 할당 전략별로 정리하면 다음과 같다.
직접 할당: em.persist()를 호출하기 전, 어플리케이션에서 직접 식별자 값을 할당해야 한다.
SEQUENCE: 데이터베이스 시퀀스에서 식별자 값을 획득한 후, 영속성 컨텍스트에 저장한다.
TABLE: 데이터베이스 시퀀스 생성용 테이블에서 식별자 값을 획득한 후, 영속성 컨텍스트에 저장한다.
IDENTITY: 데이터베이스에 엔티티를 저장해서 식별자 값을 획득한 후, 영속성 컨텍스트에 저장한다.

7. 필드와 컬럼 매핑: 레퍼런스

1. @Column

객체의 속성을 테이블 컬럼에 매핑하는 어노테이션으로 가장 많이 사용되며 기능도 많다.
속성은 다음과 같다.
name: 필드와 매핑할 테이블의 컬럼 명을 작성한다.
insertable: 엔티티 저장 시 이 필드도 같이 저장한다. false로 설정하면 이 필드는 데이터베이스에 저장하지 않는다. 읽기 전용일 때 사용한다.
updatable: 엔티티 수정 시, 이 필드도 같이 수정한다. false로 설정하면 데이터베이스에 수정하지 않는다.
table: 하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용한다.
nullable(DDL): null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시 not null 제약조건이 추가된다.
unique(DDL): @TableuniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다. 만약 두 컬럼 이상인 경우, uniqueContsraints를 사용해야 한다.
columnDefinition(DDL): 데이터베이스 컬럼 정보를 제공할 수 있다.
length(DDL): 문자 길이 제약조건, String 타입에만 사용한다.
precision, scale(DDL): BigDecimal 타입에서 사용한다. precision은 소수점을 포함한 전체 자릿수를 scale은 소수의 자릿수다. 아주 큰 숫자나 정밀한 소수를 다루어야할 때 사용한다.

2. @Enumerated

자바의 enum 타입을 매핑할 때 사용한다.
속성은 다음과 같다.
value
EnumType.ORDINAL(기본값): enum 순서를 데이터베이스에 저장한다.
EnumType.STRING: enum 이름을 데이터베이스에 저장한다.

3. @Temporal

날짜 타입(java.util.Date, java.util.Calender)를 매핑할 때 사용한다.
속성은 다음과 같다.
value(필수)
TemporalType.DATE: 날짜, 데이터베이스 date 타입과 매핑한다.
TemporalType.TIME: 시간, 데이터베이스 time 타입과 매핑한다.
TemporalType.TIMESTAMP: 날짜와 시간, 데이터베이스 timestamp 타입과 매핑한다.

4. @Lob

데이터베이스 BLOB, CLOB 타입과 매핑한다.
매핑하는 필드의 타입이 문자면 CLOB로 매핑하고 나머지는 BLOB로 매핑한다. 지정할 수 있는 속성은 없다.

5. @Transient

매핑하지 않을 때 적용한다. 데이터베이스에 저장하지 않고 조회하지도 않는다. 객체에 임시로 어떤 값을 보관할 때 사용한다.

6. @Access

JPA가 엔티티 데이터에 접근하는 방식을 지정한다.
필드 접근: AccessType.FIELD로 지정한다. 필드에 직접 접근한다.
프로퍼티 접근: AccessType.PROPERTY로 지정한다. 접근자를 사용한다.
설정하지 않으면 @Id의 위치를 기준으로 접근 방식을 설정한다.
@id가 필드에 있으면 AccessType.FIELD로 설정한 것과 같다.
@id가 속성에 있으면 AccessType.PROPERTY로 설정한 것과 같다.