Back-End/JPA
4. 엔티티 매핑
wisdom11
2022. 4. 17. 02:01
데이터베이스 스키마 자동생성
<property name="hibernate.hbm2ddl.auto" value="create" />
- 애플리케이션 실행 시점에 데이터베이스 테이블이 자동으로 생성된다.
hibernate.hbm2ddl.auto 속성
옵션 | 설명 | 개발 환경 추천 전략 |
create | 기존 테이블 삭제 후 새로 생성. drop + create |
개발 초기 CI 서버 |
create-drop | 기존 테이블 삭제 후 새로 생성 + 애플리케이션 종료 시 생성한 DDL 삭제. drop + create + drop |
CI 서버 |
update | 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다. | 개발 초기 테스트 서버 |
validate | 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않는다. DDL을 수정하지 않는다. |
테스트 서버 스테이징 서버 운영 서버 |
none | 자동 생성 기능 사용하지 않으려면 hibernate.hbm2ddl.auto 속성 자체를 삭제하거나 유효하지 않은 옵션 값을 주면 된다. (none은 유효하지 않은 옵션 값) | 스테이징 서버 운영 서버 |
*스테이징 서버: 제 운영환경의 데이터를 특정 주기마다 덤프를 떠서 데이터까지 실제 운영과 거의 비슷하게 맞추는 환경
기본 키 매핑
기본 키 생성 전략
1. 직접 할당
- 애플리케이션에서 기본 키를 직접 할당한다.
@Id private String id;
2. 자동 생성
- 대리 키를 사용한다. ⇒ @GeneratedValue
2-1. IDENTITY
- 기본 키 생성을 데이터베이스에 위임한다.
- MySQL, PostgreSQL, SQL Server, DB2
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private String id;
- 이 전략은 데이터베이스에 데이터를 insert한 후에 기본 키 값을 조회할 수 있다. em.persist()가 호출되는 즉시 insert sql이 데이터베이스에 전달된다. 즉, transactional write-behind 가 동작하지 않는다.
2-2. SEQUENCE
- 데이터베이스 시퀀스: 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트.
- 데이터베이스 시퀀스를 사용해서 기본 키를 할당한다.
- 오라클, PostgreSQL, DB2, H2
@Entity @SequenceGenerator( name = "BOARD_SEQ_GENERATOR", sequenceName = "BOARD_SEQ", // 매핑할 데이터베이스 시퀀스 이름 initialValue = 1, allocationSize = 1) public class Board { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOARD_SEQ_GENERATOR") private Long id; ... }
- em.persist()를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회한 후, 엔티티에 식별자를 할당하여 영속성 컨텍스트에 저장한다. 이 전략은 transactional write-behind가 동작한다.
- @SequenceGenerator
속성 기능 기본값 name 식별자 생성기 이름 필수 sequenceName 데이터베이스에 등록되어 있는 시퀀스 이름 hibernate_sequence initialValue DDL 생성 시에만 사용됨.
시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정한다.1 allocationSize 시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용됨) 50 catalog, schema 데이터베이스 catalog, schema 이름
매핑할 DDL
create sequence [sequenceName]
start with [initialValue] increment by [allocationSize]
최적화
- 이 전략은 데이터베이스 시퀀스를 통해 식별자를 조회하는 작업이 필요하므로, insert 시 데이터베이스와 2번 통신한다.
- JPA는 시퀀스에 접근하는 횟수를 줄이기 위해 @SequenceGenerator.allocatonSize 를 이용한다.
- 여기에 설정한 값 만큼 한 번에 시퀀스 값을 증가시키고 나서 그 만큼 메모리에 시퀀스 값을 할당한다.
2-3. TABLE
- 키 생성 테이블을 사용한다.
- 키 생성 전용 테이블을 하나 만들어 데이터베이스 시퀀스를 흉내내는 전략.
- 모든 데이터베이스에 적용할 수 있다.
- 키 생성용 테이블
sequence_name (PK) 시퀀스 이름 next_val 시퀀스 값
@Entity
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
table = "MY_SEQUENCE", // 매핑할 키 생성용 테이블
pkColumnValue = "BOARD_SEQ", allocationSize = 1)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR")
private Long id;
...
}
@TableGenerator
속성 | 기능 | 기본값 |
name | 식별자 생성기 이름 | 필수 |
table | 키 생성 테이블 이름 | hibernate_sequences |
pkColumnName | 시퀀스 컬럼 이름 | sequence_name |
valueColumnName | 시퀀스 값 컬럼 이름 | next_val |
pkColumnValue | 키로 사용할 값 이름 | 엔티티 이름 |
initialValue | 초기값, 마지막으로 생성된 값이 기준이다. | 0 |
allocationSize | 시퀀스 한 번 호출에 증가하는 수 (성능 최적화에 사용됨) |
50 |
catalog, schema | 데이터베이스 catalog, schema 이름 | |
uniqueConstraints(DDL) | 유니크 제약 조건을 지정할 수 있다. |
매핑할 DDL, 테이블명 {table}
{pkColumnName} | {valueColumnName} |
{pkColumnValue} | {initialValue} |
최적화
값을 조회하면서 select 쿼리를 사용하고, 다음 값으로 증가시키기 위해 update 쿼리를 사용한다.
즉, sequecne 전략과 비교해서 데이터베이스와 한 번 더 통신한다.
최적화하기 위해서는 @TableGenerator.allocationSize를 사용한다.
2-4. AUTO
데이터베이스 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다.
ex) 오라클 → SEQUENCE, MySQL → IDENTITY
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
- @GeneratedValue 의 기본값은 AUTO 이다. → strategy 생략 가능
- 데이터베이스를 변경해도 코드를 수정할 필요가 없다는 장점이 있다.
- 키 생성 전략이 아직 확정되지 않은 개발 초기 단계나 프로토타입 개발 시 편리하게 사용할 수 있다.
- AUTO를 사용할 때 SEQUENCE, TABLE 전략이 선택되면 시퀀스 혹은 키 생성용 테이블을 미리 만들어 두어야 한다. 만약 스키마 자동 생성 기능을 사용한다면 하이버네이트가 기본값을 사용해서 적절한 시퀀스나 키 생성용 테이블을 만들어준다.
필드와 컬럼 매핑
@Column
속성 | 기능 | 기본값 |
name | 필드와 매핑할 테이블의 컬럼 이름 | 객체의 필드 이름 |
nullable | null 허용 여부. false → not null 제약 조건 | true |
unique | 한 컬럼에 유니브 제약조건을 건다. 2개 이상의 컬럼 조합에 유니크 제약조건을 사용하려면 클래스에 @Table.uniqueConstraints를 사용해야 한다. |
|
length | 문자 길이 제약조건. String 타입만 지원. | 255 |
precision, scale | precision은 소수점을 포함한 전체 자릿수. scale은 소수의 자릿수. BigDecimal, BigInteger 타입만 지원. (double, float은 지원X) 아주 큰 숫자나 정밀한 소수를 다루어야 할 때 사용한다. |
precision=19, scale=2 |
insertable | 엔티티 저장 시 필드를 저장한다. false → 읽기 전용 | true |
updatable | 엔티티 수정 시 필드를 수정한다. false → 읽기 전용 | true |
table | 하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용한다. 지정한 필드를 다른 테이블에 매핑할 수 있다. |
현재 클래스가 매핑된 테이블 |
columnDefinition | 데이터베이스 컬럼 정보를 직접 줄 수 있다. |
@Enumerated
자바의 enum 타입 매핑 시 사용한다.
속성 | 기능 | 기본값 |
value | EnumType.ORDINAL: enum 순서를 데이터베이스에 저장 EnumType.STRING: enum 이름을 데이터베이스에 저장 |
EnumType.ORDINAL |
ORDINAL의 경우, enum의 순서를 변경할 수 없다는 것에 주의해야 한다.
@Temporal
날짜 타입 (Date, Calendar)를 매핑할 때 사용한다.
속성 | 기능 | 기본값 |
value | TemporalType.DATE: 데이터베이스 date 타입과 매핑 (날짜) TemporalType.TIME: 데이터베이스 time 타입과 매핑 (시간) TemporalType.TIMESTAMP: 데이터베이스 timestamp 타임과 매핑 (날짜와 시간) |
필수 |
- 생략 시, 자바의 Date와 가장 유사한 timestamp로 정의된다. (데이터베이스 방언에 따라 datetime 혹은 timestamp 로 정의된다.)
@Lob
데이터베이스 BLOB, CLOB 타입과 매핑한다.
매핑하는 필드 타입이 문자인 경우 CLOB, 나머지는 BLOB으로 매핑한다.
- CLOB: char[], String, java.sql.CLOB
- BLOB: byte[], java.sql.BLOB
@Transient
이 필드는 매핑하지 않는다. 데이터베이스에 저장하지 않고 조회하지도 않는다.
객체에 임시로 어떤 값을 보관하고 싶을 때 사용한다.
@Access
JPA가 엔티티 데이터에 접근하는 방식을 지정한다.
- AccessType.FIELD: 필드에 직접 접근한다. private이어도 접근할 수 있다.
- AccessType.PROPERTY: 접근자(Getter)를 통해 접근한다.
728x90