Chapter 4: 엔티티 매핑
1. @Entity
@Entity
JPA를 사용해서 테이블과 매핑할 클래스는
@Entity
annotation을 필수로 붙여야 한다@Entity
가 붙은 class는 JPA가 관리한다
@Entity
속성name
JPA에서 사용할 엔티티 이름을 지정
보통 기본값인 클래스 이름을 사용
설정하지 않으면 클래스 이름을 그대로 사용한다 (default value)
만약 다른 패키지에 이름이 같은 엔티티 클래스가 있다면, 이름을 지정해서 충돌하지 않게 해야함!
@Entity
적용 시 주의사항기본 생성자는 필수 (파라미터가 없는 public or protected 생성자)
final class, enum, interface, inner class에는 사용할 수 없다
저장할 필드에 final을 사용하면 안 된다
2. @Table
@Table
엔티티와
매핑할 테이블
을 지정한다@Table
속성name
매핑할 테이블 이름 (default는 매핑한 엔티티 이름)
catalog
catalog 기능이 있는 데이터베이스에서 catalog를 매핑한다
schema
schema 기능이 있는 데이터베이스에서 schema를 매핑한다
uniqueConstraints (DDL)
DDL 생성 시에 유니크 제약조건을 만든다
2개 이상의 복합 유니크 제약조건도 만들 수 있다
이 기능은 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용된다
3. 다양한 매핑 사용
@Enumerated
자바의 enum을 사용하려면
@Enumerated
annotation으로 매핑해야 한다
@Temporal
자바의 날짜 타입 매핑
@Lob
길이 제한이 없는 필드에 대해 데이터베이스의 VARCHAR 타입 대신에 CLOB 타입으로 지정한다
@Lob
을 사용하면 CLOB, BLOB 타입을 매핑할 수 있다
4. 데이터베이스 스키마 자동 생성
JPA는 데이터베이스
스키마
를자동
으로생성
하는 기능을 지원한다Class의 매핑 정보를 보면 어떤 테이블에 어떤 컬럼을 사용하는지 알 수 있다
JPA는 이 매핑정보와 데이터베이스 dialect를 사용해서 데이터베이스 스키마를 생성한다
application.yml
의spring.jpa.hibernate.ddl-auto
에 아래의 속성을 주어 자동 생성 옵션을 설정할 수 있다create
기존 테이블을 삭제하고 새로 생성한다
DROP + CREATE
create-drop
create 속성 + 애플리케이션 종료 시 생성한 DDL 제거
DROP + CREATE + DROP
update
데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다
validate
데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고, 애플리케이션을 실행하지 않는다
이 설정은 DDL을 수정하지 않는다
none
자동 생성 기능을 사용하지 않으려면 유효하지 않은 옵션값을 주면 된다
none은 유효하지 않은 옵션값이다
자동 생성되는 DDL은 지정한
데이터베이스 dialect
에 따라 달라진다스키마 자동 생성 기능을 사용하면 애플리케이션 실행 시점에 데이터베이스 테이블이 자동으로 생성되므로 개발자가 테이블을 직접 생성하는 수고를 덜 수 있다
but, 스키마 자동 생성 기능이 만든 DDL은 운영 환경에서 사용할 만큼 완벽하지는 않으므로 개발 환경에서 사용하거나 매핑을 어떻게 해야 하는지 참고하는 정도로만 사용하는 것이 좋다
HBM2DDL 주의사항
운영 서버에서 create, create-drop, update처럼
DDL을 수정하는 옵션
은 절대 사용하면 안 된다개발 서버나 개발 단계에서만 사용해야 한다
이 옵션들은 운영중인 데이터베이스의 테이블이나 컬럼을 삭제할 수 있다
개발 환경에 따른 추천 전략
개발 초기 단계
create or update
테스트 서버
update or validate
스테이징 & 운영 서버
validate or none
이름 매핑 전략 변경하기
자바는 카멜(Camel) 표기법, 데이터베이스는 언더스코어(_)를 주로 사용한다
hibernate.ejb.naming_strategy
속성을 사용해서 이름 매핑 전략을 변경할 수 있다
5. DDL 생성 기능
@Column
매핑정보의nullable
속성 값을 false로 지정하면 자동 생성되는 DDL에not null
제약조건을 추가할 수 있다그리고
length
속성 값을 사용하면 자동 생성되는 DDL에 문자의 크기를 지정할 수 있다
@Column
의length
와nullable
속성과 같은 기능들은 DDL을 자동으로 생성할 때만 사용되고, JPA의 실행 로직에는 영향을 주지 않는다따라서 스키마 자동 생성 기능을 사용하지 않고 직접 DDL을 만든다면 사용할 이유가 없다
그래도 이 기능을 사용하면 애플리케이션 개발자가 엔티티만 보고도 손쉽게 다양한 제약 조건을 파악할 수 있는 장점이 있다
6. 기본 키 매핑
JPA가 제공하는 데이터베이스 기본 키 생성 전략
직접 할당
기본 키를 애플리케이션에서 직접 할당
자동 생성 (대리 키 사용 방식)
IDENTITY
기본 키 생성을 데이터베이스에 위임
SEQUENCE
데이터베이스 시퀀스를 사용해서 기본 키를 할당
TABLE
키 생성 테이블을 사용
기본 키를 직접 할당하려면
@Id
만 사용하면 되고, 자동 생성 전략을 사용하려면@Id
에@GeneratedValue
를 추가하고 원하는 키 생성 전략을 선택하면 된다
6-1. 기본 키 직접 할당 전략
기본 키를 직접 할당하려면
@Id
로 매핑하면 된다@Id
적용 가능 자바 타입자바 기본형
자바 Wrapper 형
String
java.util.Date
java.sql.Date
java.math.BigDecimal
java.math.BigInteger
기본 키 직접 할당 전략은
em.persist()
로 엔티티를저장하기 전
에 애플리케이션에서 기본 키를 직접 할당하는 방법이다
6-2. IDENTITY 전략
기본 키 생성을
데이터베이스에 위임
하는 전략이다데이터베이스에 값을 저장하고 나서야 기본 키 값을 구할 수 있을 때 사용한다
이 전략을 사용하면 JPA는 기본 키 값을 얻어오기 위해 데이터베이스를
추가로 조회
한다
사용 방법
ex)
MySQL의
AUTO_INCREMENT
기능은 데이터베이스가 기본 키를 자동으로 생성해 준다
최적화
IDENTITY 전략은 데이터를 데이터베이스에 INSERT한 후에 키 값을 조회할 수 있다
따라서 엔티티에 식별자 값을 할당하려면, JPA는 추가로 데이터베이스를 조회해야 한다
JDBC3에 추가된
Statement.getGeneratedKeys()
를 사용하면 데이터를 저장하면서 동시에 생성된 기본 키 값도 얻어올 수 있다하이버네이트는 이 method를 사용해서 데이터베이스와 한 번만 통신한다
주의
엔티티가 영속 상태가 되려면 식별자가 반드시 필요하다
그런데 IDENTITY 식별자 생성 전략은 엔티티를 데이터베이스에 저장해야 식별자를 구할 수 있으므로,
em.persist()
를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달된다따라서 이 전략은
트랜잭션
을 지원하는쓰기 지연
이 동작하지 않는다
6-3. SEQUENCE 전략
데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한
데이터베이스 오브젝트
다SEQUENCE 전략은 이 시퀀스를 사용해서 기본 키를 생성한다
SEQUENCE 전략은 시퀀스를 지원하는 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있다
SEQUENCE 전략은
em.persist()
를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서식별자
를조회
한다그리고 조회한 식별자를
엔티티
에할당
한 후에 엔티티를영속성 컨텍스
트에저장
한다이후 트랜잭션을
커밋
해서플러시
가 일어나면, 엔티티를 데이터베이스에 저장한다6-2의
INDENTITY
전략은 먼저 엔티티를 데이터베이스에 저장한 후에 식별자를 조회해서 엔티티의 식별자에 할당한다
@SequenceGenerator
속성속성기능기본값name
식별자 생성기 이름
필수
sequenceName
데이터베이스에 등록되어 있는 시퀀스 이름
hibernate_sequence
initialName
DDL 생성 시에만 사용됨 (시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다!)
1
allocationSize
시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용됨)
50
catalog, schema
데이터베이스 catalog, schema 이름
x
주의!
SequenceGenerator.allocationSize
의 기본값이 50인 것에 주의해야 한다JPA가 기본으로 생성하는 데이터베이스 시퀀스는 아래와 같으므로, 시퀀스를 호출할 때마다 값이 50씩 증가한다
데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다
SEQUENCE 전략과
최적화
SEQUENCE 전략은 데이터베이스 시퀀스를 통해
식별자를 조회
하는추가 작업
이 필요하다따라서 데이터베이스와 2번 통신한다
식별자를 구하려고 데이터베이스 시퀀스를 조회한다
조회한 시퀀스를 기본 키 값으로 사용해 데이터베이스에 저장한다
JPA는 시퀀스에 접근하는 횟수를 줄이기 위해
@SequenceGenerator.allocationSize
를 사용한다해당 속성에 설정한 값만큼
한 번에 시퀀스를 증가
시키고 나서, 그만큼 메모리에 시퀀스 값을 할당한다ex)
allocationSize
값이 50이면 시퀀스를 한 번에 50 증가시킨 다음에 1~50까지는 메모리에서 식별자를 할당한다그리고 51이 되면 시퀀스 값을 100으로 증가시킨 다음 51~100까지 메모리에서 식별자를 할당한다
장점
시퀀스 값을
선점
하므로 여러 JVM이 동작해도 기본 키 값이 충돌하지 않는다
단점
데이터베이스에 직접 접근해서 데이터를
등록
할 때, 시퀀스 값이 한 번에 많이 증가한다는 점을 염두해두어야 한다이런 상황이 부담스럽고, INSERT 성능이 중요하지 않으면
allocationSize
의 값을 1로 설정하면 된다
6-4. TABLE 전략
TABLE 전략은
키 생성 전용 테이블
을 하나 만들고, 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략이다이 전략은 테이블을 사용하므로,
모든 데이터베이스
에적용
할 수 있다
ex)
@TableGenerator
를 사용해서 테이블 키 생성기를 등록한다GenerationType.TABLE
을 사용하여 TABLE 전략을 사용함을 명시한다@GeneratedValue.generator
에 테이블 키 생성기를 지정한다
TABLE 전략은 시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식이 같다
@TableGenerator
속성속성기능기본값name
식별자 생성기 이름
필수
table
키생성 테이블명
hibernate_sequences
pkColumnName
시퀀스 컬럼명
sequence_name
valueColumnName
시퀀스 값 컬럼명
sequence_name
pkColumnValue
키로 사용할 값 이름
엔티티 이름
initialValue
초기값 (마지막으로 생성된 값이 기준!)
0
allocationSize
시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용됨)
50
catalog, schema
데이터베이스 catalog, schema 이름
x
uniqueConstraints (DDL)
유니크 제약 조건을 지정할 수 있다
x
TABLE 전략과
최적화
TABLE 전략은 값을 조회하면서 SELECT 쿼리를 사용하고, 다음 값으로 증가시키기 위해 UPDATE 쿼리를 사용한다
SEQUENCE 전략과 비교해서 데이터베이스와
한 번 더 통신
하는단점
이 있다
TABLE 전략을 최적화하려면,
@TableGenerator.allocationSize
를 사용하면 된다최적화 방법은 위의 SEQUENCE 전략과 동일!
6-5. AUTO 전략
AUTO는 선택한 데이터베이스 dialect에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다
AUTO 전략의
장점
은 데이터베이스를 변경해도코드를 수정할 필요가 없다
는 것이다특히 키 생성 전략이 아직 확정되지 않은 개발 초기 단계나 프로토타입 개발 시 편리하게 사용할 수 있다
AUTO를 사용할 때, SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다
만약
스키마 자동 생성
기능을 사용한다면, 하이버네이트가기본값
을 사용해서 적절한 시퀀스나 키 생성용 테이블을 만들어 준다
6-6. 권장하는 식별자 선택 전략
JPA는 모든 엔티티에 일관된 방식으로
대리 키
사용을 권장한다비즈니스 요구사항은 계속해서 변하는데, 테이블은 한 번 정의하면 변경하기 어렵다
그런 면에서 외부 풍파에 쉽게 흔들리지 않는 대리 키가 일반적으로 좋은 선택!
7. 필드와 컬럼 매핑: 레퍼런스
7-1. @Column
@Column
객체 필드를 테이블 컬럼에 매핑한다
속성 중 name, nullable이 주로 사용되고 나머지는 잘 사용되지 않는다
속성
nullable(DDL)
null 값의 허용 여부를 설정한다
false로 설정하면, DDL 생성 시에
not nul
제약 조건이 붙는다
7-2. @Enumerated
@Enumerated
자바의 enum 타입을 매핑할 때 사용한다
속성
value
EnumType.ORDINAL
(기본값)enum
순서
를 데이터베이스에 저장장점
데이터베이스에 저장되는 데이터 크기가 같다
단점
이미 저장된 enum의 순서를 변경할 수 없다
EnumType.STRING
enum
이름
을 데이터베이스에 저장장점
저장된 enum의 순서가 바뀌거나 enum이 추가되어도 안전한다
단점
데이터베이스에 저장되는 데이터 크기가 ORDINAL에 비해서 크다
7-3. @Temporal
@Temporal
날짜 타입 (java.util.Date, java.util.Calendar) 을 매핑할 때 사용한다
자바의 Date 타입에는 년월일 시분초가 있지만, 데이터베이스에는 date(날짜), time(시간), timestamp(날짜와 시간) 라는 세 가지 타입이 별도로 존재한다
@Temporal
을 생략하면 자바의 Date와 가장 유사한timestamp
로 정의된다but, timestmp 대신에 datetime을 예약어로 사용하는 데이터베이스도 있는데, 데이터베이스 dialect 덕분에 애플리케이션 코드는 변경하지 않아도 된다
데이터베이스 방언에 따라 생성되는 DDL
datetime: MySQL
timestamp: H2, 오라클, PostgreSQL
7-4. @Lob
@Lob
데이터베이스 BLOB, CLOB 타입과 매핑한다
속성
@Lob
에는 지정할 수 있는 속성이 없다대신에 매핑하는 필드 타입이
문자
면CLOB
으로 매핑하고,나머지
는BLOB
으로 매핑한다
7-5. @Transient
@Transient
이 필드는 매핑하지 않는다
데이터베이스에 저장하지 않고, 조회하지도 않는다
객체에
임시로 어떤 값을 보관
하고 싶을 때 사용한다
7-6. @Access
@Access
JPA가 엔티티 데이터에 접근하는 방식을 지정한다
필드 접근
AccessType.FIELD로 지정한다
필드에 직접 접근한다
필드 접근 권한이 private이어도 접근할 수 있다
프로퍼티 접근
AccessType.PROPERTY로 지정한다
접근자(Getter)
를 사용한다
@Access
를 설정하지 않으면,@Id
의 위치를 기준으로 접근 방식이 결정된다@Id
가 필드에 있으면,@Access(AccessType.FIELD)
로 설정한 것 과 같다@Id
가 프로퍼티에 있으면,@Access(AccessType.PROPERTY)
로 설정한 것과 같다
Last updated