elevne's Study Note
JPA Entity 매핑 본문
JPA 를 사용하며 가장 중요한 일은 엔티티와 테이블을 정확하게 매핑하는 것이라고 한다.
@Entity: 테이블과 매핑할 클래스에 붙여준다. 해당 클래스에는 기본 생성자가 필수이며 (파라미터가 없는 public/protected 생성자) final class, enum, interface, inner class 에는 사용할 수 없다. 저장할 필드에는 final 을 사용해서도 안된다.
@Table: 엔티티와 매핑할 테이블을 지정한다.
속성 | 기능 |
name | 매핑할 테이블 이름 |
catalog | catalog 기능이 있는 데이터베이스에서 catalog 매핑 |
schema | schema 기능이 있는 데이터베이스에서 schema 매핑 |
uniqueConstraints (DDL) | DDL 생성 시에 유니크 제약조건을 만든다. 2 개 이상의 복합 유니크 제약조건도 만들 수 있다. 이 기능은 스키마 자동 생성 기능을 사용해서 DDL 을 만들 때만 사용된다. |
JPA 는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원한다. 클래스의 매핑 정보를 보면 어떤 테이블에 어떤 컬럼을 사용하는지 알 수 있다. JPA 는 이 매핑정보와 데이터베이스 방언을 사용하여 데이터베이스 스키마를 생성한다. persistence.xml 에 아래 property 를 살펴본다.
<property name="hibernate.hbm2ddl.auto" value="create" />
위 value 는 create 로 지정되어있다. 위 속성을 추가하면 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다. create 외에도 create-drop (create 옵션에 추가로 애플리케이션 종료 시 생성한 DDL 제거), update (데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경사항만 수정), validate (데이터베이스 테이블과 엔티티 매핑정보를 비교하여 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않는다. 이 옵션은 DDL 을 수정하지 않음) 를 사용할 수 있다.
DDL 생성 기능들을 더 사용해볼 수 있다. 아래와 같이 @Column 에 추가 옵션들을 넣어볼 수 있다.
@Column(name = "NAME", nullable = false, length = 10)
@Table 의 uniqueConstraints 속성도 사용해볼 수 있다.
@Entity
@Table(name = "MEMBER", uniqueConstraints = {@UniqueConstraint(
name = "NAME_AGE_UNIQUE",
columnNames = {"NAME", "AGE"}
)})
@Getter
@Setter
public class Member {
테이블 생성 정보를 확인해보면 유니크 제약 조건이 추가되었다. 이런 기능들은 단지 DDL 을 자동 생성할 때만 사용되고 JPA 실행 로직에는 영향을 주지 않는다.
@Id, PK 값을 다룰 때에는 JPA 에서 두 가지 키 생성 전략을 제공한다. 기본 키를 애플리케이션에서 직접 할당하는 직접 할당 방식, 대리 키를 사용하는 자동 생성 방식이다. 기본 키를 직접 할당하는 경우에는 @Id 만 사용하면 된다. 자동 생성을 사용할 때는 @GeneratedValue 를 사용, 키 생성 전략을 선택한다.
- IDENTITY: 기본 키 생성을 데이터베이스에 위임. 주로 MySQL, PostgreSQL, SQL Server, DB2 에서 사용
- SEQUENCE: 데이터베이스 시퀀스를 사용해서 기본 키 할당. (시퀀스: 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트) Oracle, PostgreSQL, DB2, H2 데이터베이스에서 사용할 수 있음
- TABLE: 키 생성 테이블 사용
- AUTO: 데이터베이스에 따라 위 3 개의 전략 중 하나를 자동으로 선택
자동 생성 전략이 다양한 이유는 데이터베이스 벤더마다 지원하는 방식이 다르기 때문이다. (e.g., Oracle 에서는 시퀀스를 제공하지만 MySQL 은 제공하지 않는다. 대신에 MySQL 은 기본 키 값을 자동으로 채워주는 AUTO_INCREMENT 기능을 제공한다)
SEQUENCE 를 사용할 때는 데이터베이스의 시퀀스를 매핑해야 한다.
@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;
}
@SequenceGenerator 을 사용하여 BOARD_SEQ_GENERATOR 이라는 시퀀스 생성기를 등록한다. 그리고 sequenceName 속성으로 BOARD_SEQ 를 지정했는데 JPA 는 이 시퀀스 생성기를 실제 데이터베이스의 BOARD_SEQ 시퀀스와 매핑한다. 그 다음으로 @GeneratedValue 내에 generator="BOARD_SEQ_GENERATOR" 로 넣어주어 등록한 시퀀스 생성기를 선택한다.
SEQUENCE 전략은 데이터베이스 시퀀스를 통해 식별자를 조회하는 추가작업이 필요하다. 따라서 데이터베이스와 2 번 (식별자를 구하려고 데이터베이스와 통신, 조회한 시퀀스를 기본 키 값으로 사용해 데이터베이스에 저장) 통신하게 된다. JPA 는 시퀀스에 접근하는 횟수를 줄이기 위해 @SequenceGenerator.allocationSize 를 사용한다. 여기에 설정한 값만큼 한 번에 시퀀스 값을 증가시키고 나서 그만큼 메모리에 시퀀스 값을 할당한다. (e.g., allocationSize 가 50 이면 시퀀스를 한 번에 50 증가시킨 다음, 1 ~ 50 까지는 메모리에서 식별자를 할당하고, 51 이 되면 시퀀스 값을 100 으로 증가시킨 다음 51 ~ 100 을 메모리에서 할당) 이 최적화 방법은 시퀀스 값을 선점하므로 여러 JVM 이 동시에 동작해도 기본 키 값이 충돌하지 않는다. 한편 데이터베이스에 직접 접근하여 데이터를 등록할 때 시퀀스 값이 한 번에 많이 증가한다는 점을 염두에 두어야 한다.
TABLE 전략은 키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내내는 전략이다. TABLE 전략을 사용하려면 먼저 키 생성 용도로 사용할 테이블을 만든다.
CREATE TABLE MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key (sequence_name)
)
sequence_name 컬럼을 시퀀스 이름으로 사용하고 next_val 컬럼을 시퀀스 값으로 사용한다.
@Entity
@TableGenerator(
name = "BOARD_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = "BOARD_SEQ", allocationSize = 1
)
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "BOARD_SEQ_GENERATOR")
private Long id;
}
MY_SEQUENCE 테이블을 사용하여 BOARD_SEQ_GENERATOR 이라는 이름의 식별자 생성기를 정의한다. pkColumnValue 로 키로 사용할 값 이름을 지정, allocationSize 로 시퀀스 한 번 호출에 증가하는 수를 지정한다.
기본 키를 선택하는 방식은 크게 두 가지가 있다. 첫 번째는 자연 키, 비즈니스에 의미가 있는 키 (주민번호, 이메일, ...) 를 사용하는 것이다. 두 번째는 대리 키, 비즈니스와 관련 없는 임의로 만들어진 키 (auto_increment, oracle sequence, ...) 를 사용하는 것이다. 자연 키보다는 대리 키를 사용하는 것이 권장된다. 데이터베이스의 기본 키는 null 이여서는 안되고, 유일해야 하며 변할 수 없다. 이러한 3 가지 조건을 항상 만족해야하기에 대리 키가 좋을 수 있다. 현실과 비즈니스 규칙은 생각보다 쉽게 변하기에 대리 키가 권장된다.
엔티티 필드와 컬럼을 매핑할 때는 아래 애노테이션들이 사용된다.
매핑 애노테이션 | 설명 |
@Column | 컬럼 매핑 |
@Enumerated | 자바의 enum 타입 매핑 |
@Temporal | 날짜 타입 매핑 |
@Lob | BLOB, CLOB 타입 매핑 |
@Transient | 특정 필드를 데이터베이스에 매핑하지 않음 |
@Access | JPA 가 엔티티에 접근하는 방식 지정 (AccessType.FILED-필드 직접 접근/ AccessType.PROPERTY-getter) |
Reference:
자바 ORM 표준 JPA 프로그래밍
'Backend > JPA 프로그래밍' 카테고리의 다른 글
JPA - Proxy, Cascade, Orphan (0) | 2023.07.11 |
---|---|
JPA 고급매핑 (0) | 2023.07.09 |
JPA N:M 관계 (0) | 2023.07.06 |
JPA 연관관계 매핑 (0) | 2023.07.05 |
JPA 영속성 관리 (0) | 2023.07.03 |