JPA

엔티티 매핑, 기본 키 매핑

salmon16 2023. 8. 27. 14:05

@Entity

  • 객체와 테이블을 매핑하기 위해서 @Entity 애노테이션을 사용한다
  • @Entity 애노테이션을 사용하면 그 객체는 JPA가 관리한다.
  • 관리되는 객체는 기본 생성자(파라미터가 없는)가 필수적으로 필요하다.(public, protected)
  • 저장할 필드에 final을 사용하면 안 된다.
  • final, enum, interface, inner 클래스에 사용이 불가하다.
  • Entity 중 name에 대해 알아보자
  • JPA에서 사용할 엔티티 이름을 지정한다 디폴트 값은 클래스의 이름이다. 
  • 디폴트 값을 사용하는 것을 권장한다 ( 같은 이름의 클래스가 없을 때)

 

@Table

엔티티와 매핑할 테이블을 지정한다.

기본 값으로는 엔티티의 이름을 사용한다.

 

기본 키는 @Id 애노테이션을 사용한다.

 

매핑애노테이션 정리

  • Column : 컬럼 매핑
  • Temporal : 날짜 타입 매핑
  • Enumerated : enum 타입 매핑
  • Lob : BLOB, CLOB 매핑
  • Transient : 해당 필드를 매핑하지 않음

@Column의 속성에 대해서 좀 더 알아보자

  • name : 필드와 매핑할 테이블의 컬럼 이름 기본값은 객체의 필드 이름이다
  • insertable, updatable : 등록이나 변경 가능 여부 기본값은 true
  • nullable : null값 허용 여부 기본값 true
  • unique : 한 컬럼에 간단히 유니크 제 약조건을 걸 때 사용
  • length : 문자 길이 제약 조건 String 타입에만 가능하다 기본값 255
  • precision, scale : BigDecimal 타입에서 사용 precision은 소수점 포함한 전체 자릿수를 scale은 소수 자릿수다

@Enumerated

자바 enum타입 매핑시 사용한다

속성의 value에 ORDINAL을 사용하면 안 된다 기본값이 ORDINAL로 되어있다

EnumType.STRING을 사용해야 한다

ORDINAL을 사용하면 enum을 수로 표현하는데  예를 들어 아래와 같은 enum이 있다고 생각해 보자

public enum OrderStatus {
    ORDER, CANCLE
}

원래 위 enum을 사용하며 db에 값을 ORDER = 0, CANCLE = 1로 저장을 했다

public enum OrderStatus {
    DELAY, ORDER, CANCLE
}

DELAY라는 상황이 추가로 생겨서 위와 같이 enum을 수정하고 다시 사용하면 DELAY = 0, ORDER = 1, CANCLE = 2로 새로운 데이터들이 저장되는데 이러면 이전에 저장되었던 데이터들과 문제가 발생한다. 그래서 STRING 타입을 권장한다.

@Temporal

날짜 타입을 매핑할 때 사용한다

속성으로 value = TemporalType.DATE, TemporalType.TIME, TemporalType.TIMESTAMP 들이 있다. 

각 데이터 베이스의 date 타입, time 타입, timestamp타입과 매핑하는데

LocalDate, LocalDateTIme 타입을 자바에서 사용하면 최신 하이버네이트가 자동으로 지원해 준다.

@Lob

긴 문자나 숫자를 저장핼 때 사용한다

필드 타입이 문자면 CLOB, 나머지는 BLOB에 매핑된다.

@Transient

해당 필드를 매핑하지 않는다는 애노테이션이다

 

기본 키 매핑

기본 키 매핑 방식에는 직접 할당, 자동 생성 방식이 있다.

자동 생성 방식에는 IDENTITY, SEQUENCE, TABLE, AUTO 4가지 방식이 있다.

하나씩 알아보자

 

직접 할당

직접 할당하려면 em.persist()를 하기 전에 Id를 직접 할당해 주어야(setter, 생성자를 통해) 한다.

직접 할당은 @Id 애노테이션만 사용해도 된다 

 

IDENTITY

주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용한다

IDENTITY 방식은 데이터 베이스에게 기본 키 생성을 위임하는 방식이다.

JPA는 트랜잭션 커밋 시점에 INSERT SQL을 실행한다. 

하지만 IDENTITY 전략은 데이터를 DB에 저장한 후 기본 키 값을 생성하므로 

em.persist() 시 (기본 키, 값)을 영속성 컨텍스트에 저장하기 위해 기본 키가 필요하므로 키 값을 얻기 위해 em.persist()를 하면 insert SQL을 실행해서 기본 키를 받아온다. insert할 때 키 값으로 null을 보낸다.

그래서 IDENTITY 방식은 쓰기 지연이 동작하지 않는다.

@Entity 
public class Member { 
 	@Id 
 	@GeneratedValue(strategy = GenerationType.IDENTITY) 
 	private Long id;

 

 

SEQUENCE

 

데이터 베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터 베이스 오브젝트를 사용한다.

오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용

 

데이터 베이스의 오브젝트에서 미리 allocationsSize 만큼 시퀀스를 받아와서(call next value) 메모리에 저장하며 사용한다. 사용하다 부족하면 다시 데이터 베이스에서 시퀀스를 받아와서 또 사용한다. 만약 시퀀스를 다 사용하기 전에 어플리케이션이 종료될 경우, 남은 시퀀스는 사라지고 다시 사용할 수 없는 상태가 된다. 예를 들어 1-50번까지의 시퀀스 중 20번까지 사용하고 21-50번은 사용하지 않은 상태로 어플리케이션이 종료되고 다시 시작되면 51 시퀀스부터 시작하게 된다.

 

필요한 경우 버퍼링이 가능하다

 

IDENTITY 방식과 다르게 insert쿼리를 보낼 때 null이 아닌 시퀀스값을 보내게 된다.

 

테이블 마다 시퀀스를 다르게 설정하고 싶으면 @SequenceGenerator 통해 매핑하면 된다.

@Entity 
@SequenceGenerator( 
 	name = “MEMBER_SEQ_GENERATOR", 
 	sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
 	initialValue = 1, allocationSize = 50) 
public class Member { 
 	@Id 
 	@GeneratedValue(strategy = GenerationType.SEQUENCE, 
 	generator = "MEMBER_SEQ_GENERATOR") 
 	private Long id;

 

@SequenceGenerator의 속성을 알아보자

  • name = 식별자 생성기 이름
  • sequenceName = 데이터베이스에 등록되어 있는 시퀀스 이름
  • initialValue = DDL 생성시에만 사용되고 시퀀스 DDL을 생성할 때 처음 시작하는 수
  • allocationsSize = 시퀀스 한 번 호출에 증가하는 수 보통 50을 사용한다.
  • catalog, schema = 데이터베이스 catalog, schema 이름

TABLE

키 생성 테이블을 만들어서 데이터베이스 시퀀스 전략을 흉내 내는 전략이다

모든 데이터베이스에 적용가능하다

@Entity 
@TableGenerator( 
 	name = "MEMBER_SEQ_GENERATOR", 
 	table = "MY_SEQUENCES", 
 	pkColumnValue = “MEMBER_SEQ", allocationSize = 50) 
public class Member { 
	 @Id 
 	@GeneratedValue(strategy = GenerationType.TABLE, 
 	generator = "MEMBER_SEQ_GENERATOR") 
 	private Long id;

 

적용 하면 테이블 생성 SQL이 나간다

create table MY_SEQUENCES ( 
 sequence_name varchar(255) not null, 
 next_val bigint, 
 primary key ( sequence_name ) 
)

최적화된 테이블을 직접 사용하기 때문에 성능상의 이슈가 있어 잘 사용하기 않는다.

@TableFenerator 속성

속성 설명 기본값
name 식별자 생성 이름 필수
table 키 생성 테이블 이름 hibernate_sequences
pkColumnName 시퀀스 컬럼명 sequence_name
valueColumnNa 시퀀스 값 컬럼명 next_val
pkColumnValue 키로 사용할 값 이름 엔티티 이름
initialValue 초기 값, 마지막으로 생성된 값이 기준이다 0
allocationSize 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨) 50으로 보통 설정한다
catalog, schema 데이터베이스 catalog, schema 이름  
uniqueConstraint s(DDL) 유니크 제약 조건을 지정할 수 있다.  

AUTO

데이터베이스의 특성(방언)에 따라 위 세 가지 전략을 자동으로 지정한다.

기본 설정 값이다.

@GeneratedValue(strategy = GenerationType.AUTO)

권장하는 식별자 전략

기본 키의 제약 조건은 null이 아니여야 하고 유일하며 변경이 되면 안 된다.

이 조건을 만족하는 자연키는 찾기 어렵다.

그래서 대리키/대체키를 사용하자!

 

자연키 : 비즈니스적으로 의미가 있는 (주민등록 번호, 전화번호)

대리키/대체키 : 비즈니스랑 상관없고 랜덤 값 

 

타입으로는 어떤 타입을 사용해야 할까?

  • int는 0이 있어서 x
  • Interger 10억 정도까지만 가능하다
  • Long Interger의 2배 정도 가능하다

Long을 사용하자 10억이 넘어갔을 때 타입을 바꾸는 일은 어렵기 때문에 Long으로 사용

크기가 Interger에 비해 2배 크지만 이 비용은 어플리케이션 전체로 봤을 때 별로 안크다.

 

 결론 : Long + 대체키 + 적절한 키 생성전략을 사용하자

'JPA' 카테고리의 다른 글

상속관계 매핑  (0) 2023.08.29
다양한 연관관계 매핑  (0) 2023.08.29
연관관계 매핑, 단방향, 양방향  (0) 2023.08.28
JPA 설정 하기  (0) 2023.08.26
영속성 컨텍스트  (0) 2023.08.26