#4 엔티티 매핑
엔티티 매핑
JPA를 사용하는데 가장 중요한 일은 엔티티와 테이블을 정확히 매핑하는 것이다.
JPA는 다양한 매핑 어노테이션을 지원하는데 다음과 같이 크게 4가지로 분류할 수 있다.
● 객체와 테이블 매핑 : @Entity, @Table
● 기본 키 매핑 : @Id
● 필드와 컬름 매핑 : @Column
● 연관관계 매핑 : @ManyToOne, @JoinColumn
1. 객체와 테이블 매핑
■ @Entity
● @Entity가 붙은 클래스는 JPA가 관리, 엔티티라 한다.
● JPA를 사용해서 테이블과 매핑할 클래스는 @Entity가 필수이다.
● JPA가 엔티티 객체를 생성할 때 기본 생성자를 사용하므로, 기본 생성자가 필수이다(파라미터가 없는 public 또는 protexted 생성자).
● final, enum, interface, inner 클래스는 사용하면 안 된다.
● 저장할 필드에 final을 사용할 수 없다.
□ 속성
● name
◎ JPA에서 사용할 엔티티 이름을 지정한다.
◎ 이름을 지정하지 않으면 클래스 이름을 그대로 사용한다.
■ @Table
@Table은 엔티티와 매핑할 테이블을 지정한다.
□ 속성
● name
◎ 매핑할 테이블 이름(기본값은 엔티티 이름)
● catalog
◎ 데이터베이스 catalog 매핑
● schema
◎ 데이터베이스 schema 매핑
● uniqueConstraints
◎ DDL 생성 시에 유니크 제약 조건 생성
■ @Column
컬럼을 매핑한다.
□ 속성
● name
◎ 필드와 매핑할 테이블의 컬럼 이름(기본값은 객체의 필드 이름)
● insertable, updatable
◎ 등록, 변경 가능 여부
◎ 기본값은 TRUE
● nullable
◎ null 값의 허용 여부 설정.
◎ false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다
● unique
◎ @Table의 uniqueConstraints와 같지만 한컬럼에 간단한 유니크 제약조건을 걸때 사용된다.
● columnDefinition
◎ 데이터베이스 컬럼 정보를 직접 줄 수 있다.
◎ DDL 전용
ex) "varchar(100) default 'EMPTY'"
◎ 기본적으로 필드의 자바 타입과 방언 정보를 사용해서 자동으로 생성된다.
● length
◎ 문자 길이 제약조건, String 타입에만 사용한다.
◎ 기본값은 255
◎ DDL 전용
● precision, scale
◎ BigDecimal 타입에서 사용
◎ precision은 소수점을 포함한 전체 자릿수
◎ scale은 소수의 자릿수
◎ double, float 타입에 적용되지 않는다.
◎ 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다.
◎ DDL 전용
■ @Enumerated
자바 eunm 타입을 매핑할 때 사용
□ 속성
● value
◎ EnumType.ORDINAL : enum 순서를 데이터베이스에 저장
◎ EnumType.STRING : enum 이름을 데이터베이스에 저장
※ ORDINAL은 순서를 숫자로 저장하기 때문에 만에 하나 enum 속성이 추가되면 기존과 다르게 식별될 수 있기 때문에 절대 사용하면 안 된다.
■ Lob
데이터베이스 BLOB, CLOB 타입과 매핑
● @Lob에는 지정할 수 있는 속성이 없다.
● 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
■ @Transient
필드 매핑을 하지 않게 한다.
때문에 해당 어노테이션이 붙은 필드는 데이터베이스에 저장, 조회가 되지 않는다.
주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용된다.
2. 기본 키 매핑
■ @Id
테이블에서 사용될 PK를 지정한다.
■ @GeneratedValue
PK를 자동 생성해준다.
다음과 같은 속성으로 PK 자동 생성 메커니즘을 변경할 수 있다.
● IDENTITY
◎ 데이터베이스에 위임
◎ MYSQL
● SEQUENCE
◎ 데이터베이스 시퀀스 오브젝트 사용
◎ ORACLE
◎ @SequenceGenerator 필요
● TABLE
◎ 키 생성용 테이블 사용
◎ 모든 DB에서 사용
◎ @TableGenerator 필요
● AUTO
◎ 방언에 따라 자동 지정
◎ 기본값으로 설정되어 있다.
사용법은 다음과 같다.
@GeneratedValue(strategy = GenerationType.IDENTITY)
※ 키 생성 전략을 사용하려면 JPA 설정에 hibernate.id.new_generator_mappings=true 속성을 반드시 추가해야 한다.
□ IDENTITY 전략
● 기본 키 생성을 데이터베이스에 위임
● 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용
ex) MySQL의 AUTO_INCREMENT
EntityManager.persist()로 엔티티를 영속 상태로 만들려면 기본 키가 필요하다.
하지만 IDENTITY 전략은 DB에 기본 키 생성을 위임하기 때문에 persist() 시점에 즉시 INSERT SQL을 실행하고 DB에서 식별자를 조회한다.
즉 IDENTITY 전략을 사용하면 persist() 사용 시, 쓰기 지연이 동작하지 않는다.
□ SEQUENCE 전략
● 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다.
● 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용한다.
SEQUENCE 전략은 EntityManager.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한다.
그리고 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.
따라서 IDENTITY 전략과는 달리, 트랜잭션을 커밋해서 플러시가 일어날 때까지 SQL을 DB에 적용하지 않는다.
SEQUENCE 전략은 사용할 데이터베이스 시퀀스를 매핑해주어야 한다.
JPA에서는 @SequenceGenerator 어노테이션과 속성으로 다음과 같이 시퀀스에 여러 매핑 정보를 설정할 수 있다.
[@SequenceGenerator - SEQUENCE 전략]
@Entity
@SequenceGenerator(
name = “MEMBER_SEQ_GENERATOR",
sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
}
"MEMBER_SEQ_GENERATOR" 라는 시퀀스 생성기를 등록하고 실제 DB에 "MEMBER_SEQ" 라는 이름의 시퀀스로 매핑한다.
※ @SequenceGenerator는 @GeneratedValue 옆에 사용해도 된다.
@SequenceGenerator의 속성은 다음과 같다.
● name
◎ 식별자 생성기 일름
◎ 필수이다.
● sequenceName
◎ 데이터베이스에 등록되어 있는 시퀀스 이름
● initialValue
◎ DDL 생성 시에만 사용된다.
◎ 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다.
● allocationSize
◎ SEQUENCE 전략은 시퀀스에서 식별자를 조회하기 위해 데이터베이스와 2번 통신한다. 이 때문에 미리 일정 크기의 식별자를 증가시키고 증가된 크기만큼의 식별자는 메모리에서 할당한다.
ex) allocationSize = 50 이면, 시퀀스를 한 번에 50 증가시키고 1 ~ 50 까지는 메모리에서 식별자를 할당한다.
◎ 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용)
◎ 기본값은 50이다.
◎ INSERT 성능이 중요하지 않고 시퀀스를 한 번에 증가시키는 것이 부담스럽다면 allocationSize의 값을 1로 설정하면 된다.
● catalog, schema
◎ 데이터베이스 catalog, schema 이름
□ TABLE 전략
● 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내 내는 전략
● 모든 데이터베이스에 적용 가능하다는 장점이 있지만 테이블을 직접 만들어서 사용하기 때문에 성능을 깎아먹는다는 단점이 있다.
TABLE 전략은 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작 방식이 같다.
TABLE 전략을 사용하려면 키 생성 용도로 사용할 테이블을 만들고 매핑해야한다.
[TABLE 생성 - TABLE 전략]
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key ( sequence_name )
)
[@TableGenerator - TABLE 전략]
@Entity
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = “MEMBER_SEQ", allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
}
@TableGenerator를 사용해서 만들어 놓은 "MY_SEQUENCE" 테이블을 키 생성기로 매핑한다.
엔티티의 PK에 붙은 @GeneratedValue에는 TABLE 전략을 사용하고 generator로 @TableGenerator로 등록한 테이블 키 생성기(MEMBER_SEQ_GENERATOR)를 사용한다.
이후부터는 id 식별자 값은 MEMBER_SEQ_GENERATOR 테이블 키 생성기가 할당한다.
@TableGenerator의 속성들은 다음과 같다.
● name
◎ 식별자 생성기 이름
◎ 필수 값이다.
● table
◎ 키 생성 테이블명
● pkColumnName
◎ 시퀀스 칼럼명
● valueColumnName
◎ 시퀀스 값 컬럼명
● pkColumnValue
◎ 키로 사용할 값 이름
◎ 기본값은 엔티티 이름이다.
● initialValue
◎ 초기 값, 마지막으로 생성된 값이 기준이다.
● allocationSize
◎ 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨)
◎ 기본값은 50으로, SEQUENCE 전략과 같이 최적화할 수 있다.
● catalog, shema
◎ 데이터베이스 catalog, schema 이름
● uniqueConstraints
◎ 유니크 제약 조건을 지정할 수 있다.
□ AUTO 전략
데이터베이스 방언에 따라 앞의 세 전략 중 하나를 자동으로 선택한다.
만약 AUTO 전략을 사용할 때 SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다.
만약 스키마 자동 생성 기능을 사용한다면 하이버네이트가 기본값을 사용해서 적절한 시퀀스나 키 생성용 테이블을 만들어 준다.
■ 권장되는 기본 키 선택 전략
데이터베이스 기본 키는 다음 3가지 조건을 모두 만족해야 한다.
● null값은 허용하지 않는다.
● 유일해야 한다.
● 변해서는 안된다.
테이블의 기본키 선택 전략은 크게 자연 키(natural key)와 대리 키(surrogate key)로 나뉜다.
● 자연 키 : 비즈니스에 의미가 있는 키
ex) 주민등록번호, 이메일, 전화번호 등
● 대리 키 : 비지니스와 관련 없는 임의로 만들어진 키
비지니스 환경은 언젠가 변하고, 앞의 기본 키의 3가지 조건을 만족시키기 위해서는 자연 키 보다는 대리 키를 사용하는 것이 권장된다.
결과적으로 Long형 + 대체 키 + 키 생성 전략을 사용해서 식별자를 운용하는 것이 바람직하다고 볼 수 있다.
3. 데이터베이스 스키마 자동 생성
JPA 설정으로 DDL을 애플리케이션 실행 시점에 자동 생성할 수 있다.
※ DDL(Data Definition Language) : 데이터를 생성, 수정, 삭제하는 등, 데이터 전체 골격을 정하는 언어
ex) CREATE, ALTER, DROP 등
JPA는 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성해준다.
스키마를 자동 생성하려면 JPA 설정에 "hibernate.hbm2ddl.auto" 를 추가해야 한다.
이 속성을 추가하면 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다.
■ hibernate.hbm2ddl.auto 속성
● create
◎ 기존 테이블을 삭제하고 새로 생성한다
◎ DROP + CREATE
● create-drop
◎ create 속성에 ㅔ추가로 애플리케이션을 종료할 때 생성한 DDL을 제거한다.
◎ DROP + CREATE + DROP
● update
◎ 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다.
● validate
◎ 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않는다.
◎ 이 설정은 DDL을 수정하지 않는다.
● none
◎ 자동 생성 기능을 사용하지 않는다.
운영 서버에서 create, create-drop, update 처럼 DDL을 수정하는 옵션은 절대 사용하면 안 된다.
이 옵션들은 운영 중인 데이터베이스의 테이블이나 컬럼을 삭제할 수 있기 때문이다.
개발 초기 단계는 create 또는 update
테스트 서버는 update 또는 validate
스테이징과 운영 서버는 validate 또는 none이 권장된다.
※ JPA의 DDL 전용 기능(@Column의 nullable 속성 등)은 DDL을 자동 생성할 때만 사용되고 JAP의 실행 로직에는 영향을 주지 않는다.