elevne's Study Note

JPA Entity 매핑 본문

Backend/JPA 프로그래밍

JPA Entity 매핑

elevne 2023. 7. 4. 18:21

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)

 

 

@TableuniqueConstraints 속성도 사용해볼 수 있다.

 

 

@Entity
@Table(name = "MEMBER", uniqueConstraints = {@UniqueConstraint(
        name = "NAME_AGE_UNIQUE",
        columnNames = {"NAME", "AGE"}
)})
@Getter
@Setter
public class Member {

 

 

result

 

 

테이블 생성 정보를 확인해보면 유니크 제약 조건이 추가되었다. 이런 기능들은 단지 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