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