자바 ORM 표준 JPA 프로그래밍

[자바 ORM 표준 JPA 프로그래밍] 4장 - 엔티티 매핑

jny0 2023. 5. 1. 18:06

 

 

자바 ORM 표준 JPA 프로그래밍 | 김영한 - 교보문고

자바 ORM 표준 JPA 프로그래밍 | 자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA

product.kyobobook.co.kr

 

4장 - 엔티티 매핑

 

1. @Entity

  • 테이블과 매핑할 클래스는 @Entity 어노테이션을 필수로 붙여야 한다.
  • name : 엔티티의 이름, 보통 기본값인 클래스 이름을 사용한다.
  • 기본 생성자는 필수
  • final 클래스, enum, interface, inner 클래스에는 사용할 수 없다.
  • 저장할 필드에 final을 사용하면 안 된다.

 

2. @Table

  • @Table은 엔티티와 매핑할 테이블을 지정한다.
    • 생략하면 매핑한 엔티티 이름을 테이블 이름으로 사용

속성

  • name : 매핑할 테이블 이름
  • catalog : catalog 기능이 있는 데이터베이스에서 catalog 매핑
  • schema : schema 기능이 있는 데이터베이스에서 schema 매핑
  • uniqueConstraints : DDL 생성 시 유니크 제약조건을 만듦

 

3. 데이터베이스 스키마 자동 생성

  • JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원한다.

application.yml

spring:
  jpa:
    generate-ddl: true
    hibernate:
      ddl-auto: create
    show-sql: true // 테이블 생성 DDL 출력 가능

 

hibernate.ddl-auto 속성

  • create : 기존 테이블을 삭제하고 새로 생성한다 (DROP + CREATE)
  • create-drop : create 속성에 추가로 어플리케이션을 종료할 때 생성한 DDL을 제거한다.(DROP + CREATE + DROP) 
  • update : DB테이블과 엔티티 매핑 정보를 비교해서 변경사항만 수정한다
  • validate : DB테이블과 엔티티 매핑 정보를 비교해서 차이가 있으면 경고를 남기고 어플리케이션을 실행하지 않는다.
  • none : 자동 생성 기능을 사용하지 않음(유효하지 않은 옵션 값)

 

주의사항

  • 운영서버에서 create, create-drop, update처럼 DDL을 수정하는 옵션은 절대 사용하면 안 된다. 오직 개발 서버나 개발 단계에서만 사용해야 한다.

 

4. DDL 생성 기능

@Entity
@Table(name="MEMBER")
public class Member {

    @Id
    @Column(name="ID")
    private String id;

    @Column(name = "NAME", nullable = false, length = 10)
    private String username;
    ...
}

@Column 매핑 정보의 속성 값 지정

  • nullable : false로 지정하면 자동 생성되는 DDL에 not null 제약 조건을 추가할 수 있다.
  • length : 문자 크기 지정

다양한 제약 조건을 추가할 수 있지만 이런 기능들은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.

 

5. 기본 키 매핑

JPA가 제공하는 데이터베이스 기본 키 생성 전략

  • 직접 할당 : 기본 키를 애플리케이션에 직접 할당
  • 자동 생성 : 대리 키 사용 방식
    • IDENTITY : 기본 키 생성을 데이터베이스에 위임한다.
    • SEQUENCE : 데이터베이스 시퀀스를 사용해서 기본 키를 할당한다.
    • TABLE : 키 생성 테이블을 사용한다.

 

5.1 기본 키 직접 할당

  • @Id로 매핑
  • em.persist() 로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방식

 

5.2 IDENTITY 전략

기본 키 생성을 데이터베이스에 위임하는 전략

  • 데이터베이스에 값을 저장하고 나서야 기본 키 값을 구할 수 있을 때 사용
  • @Id@GenerateValue 어노테이션을 함께 사용
    • @GenerateValue의 strategy 속성 값을 GenerationType.IDENTITY로 지정
@Entity
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    ...
}
  • IDENTITY 전략은 ****JPA는 기본 키 값을 얻어오기 위해 데이터베이스를 추가로 조회한다.
  • 식별자를 구하기 위해 em.persist()를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달되므로, 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.

 

5.3 SEQUENCE 전략

데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오프젝트이고, SEQUENCE 전략은 이 시퀀스를 사용해서 기본 키를 생성한다.

  • 시퀀스 생성
  • @SequenceGenerator : 시퀀스 생성기 등록
  • @GenerateValue의 strategy 속성 값 GenerationType.SEQUENCE 로 지정
  • generator : 등록한 시퀀스 생성기 선택
CREATE TABLE BOARD (
    ID BIGINT NOT NULL PRIMARY KEY,
    DATA VARCHAR (255)
)

// 시퀀스 생성
CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;

// 시퀀스 매핑
@Entity
@SequenceGenerator (
    name = "BOARD_SEQ_GRNERATOR",
    sequenceName = "BOARD_SEQ", // 매핑할 데이터베이스 시퀀스 이름
    initialValue = 1, allocationSize = 1)
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOARD_SEQ_GENERATOR")
    private Long id;
    ...
}

 

IDENTITY 전략과의 차이

  • SEQUENCE 전략
    • em.persist() 를 호출할 때 먼저 데이터베이스 시퀀스를 사용해서 식별자를 조회
    • 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장
    • 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 데이터베이스에 저장
  • IDENTITY 전략
    • 먼저 엔티티를 데이터베이스에 저장한 후에 식별자를 조회해서 엔티티의 식별자를 할당

 

@SequenceGenerator 속성

속성 기능 기본값
name 식별자 생성기 이름 필수
sequenceName 데이터베이스에 등록되어 있는 시퀀스 이름 hibernate_sequence
initialValue DDL 생성 시에만 사용, 시퀀스 DDL을 생성할 때 처음 시작하는 수 지정 1
allocationSize 시퀀스 한 번 호출에 증가하는 수 50
catalog, schema 데이터베이스 catalog, schema 이름  

 

5.4 Table 전략

키 생성 전용 테이블을 하나 만들고, 이름과 값으로 사용할 컬럼을 만들어 데이터베이스 시퀀스를 흉내 내는 전략

  • 키 생성 용도로 사용할 테이블 생성
    • 시퀀스 이름 : sequence_name
    • 시퀀스 값 : next_val
  • @TableGenerator : 테이블 키 생성기 등록
  • @GenerateValue의 strategy 속성 값 GenerationType.TABLE 로 지정
  • SEQUENCE 전략과 내부 동작 방식이 같다
create TABLE MY_SEQUENCES ( // 키 생성 용도
    sequence_name varchar (255) not null,
    next_val bigint,
    primary key (sequence_name)
)

// 테이블 전략 매핑
@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;
    ...
}

 

@TableGenerator 속성

name 식별자 생성기 이름 필수
table 키 생성 테이블명 hibernate_sequences
pkColumnName 시퀀스 컬럼명 sequence_name
valueColumnName 시퀀스 값 컬럼명 next_val
pkColumnValue 키로 사용할 값 이름 엔티티 이름
initialValue 초기 값. 0
allocationSize 시퀀스 한 번 호출에 증가하는 수 50
catalog, schema 데이터베이스 catalog, schema 이름  
uniqueConstraints(DDL) 유니크 제약 조건을 지정  

 

5.5 Auto 전략

  • @GenerateValue의 strategy 속성 값 GenerationType.AUTO 로 지정
  • 선택한 데이터베이스 방언에 따라 전략을 자동으로 선택
  • 데이터베이스를 변경해도 코드를 수정할 필요가 없고, 키 생성 전략이 아직 확정되지 않은 개발 초기 단계나 프로토타입 개발 시 편리하게 사용 가능하다.
  • 시퀀스나 테이블 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어두어야 한다.

 

 

6. 필드와 컬럼 매핑 : 레퍼런스

6.1 @Column

  • 객체 필드를 테이블 컬럼에 매핑할 때 사용
속성 기능 기본 값
name 필드와 매핑할 테이블의 컬럼 이름 객체의 필드 이름
nullable null 값의 허용 여부를 설정. false로 설정하면 DDL 생성 시에 not null 제약 조건이 붙음 true
unique 한 컬럼에 간단히 유니크 제약 조건을 걸 때 사용 (@Table의 uniqueConstraints와 같음)  
columnDefinition 데이터베이스 컬럼 정보를 직접 줄 수 있다. 필드의 자바 타입과 방언 정보를 사용해서 적절한 컬럼 타입을 생성
length 문자 길이 제약 조건, String 타입에만 사용 255
precision, scale BigDecimal 타입 혹은 BigInteger 타입에서 사용. precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수. ( double, float 타입에는 적용되지 않음) precision = 19, scale = 2

 

6.2 @Enumerated

  • 자바의 enum 타입을 매핑할 때 사용
  • value
    • EnumType.ORDINAL : enum 순서를 데이터베이스에 저장
    • EnumType.STRING : enum 이름을 데이터베이스에 저장

 

6.3 @Temporal

  • 날짜 타입을 매핑할 때 사용
  • value
    • TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑
    • TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑

 

6.4 @Lob

  • 데이터베이스 CLOB, BLOB 타입과 매핑
  • 지정할 수 있는 속성이 없다.
    • 매핑하는 필드 타입이 문자면 CLOB, 나머지는 BLOB으로 매핑한다.

 

6.6 @Transient

  • 이 필드는 매핑하지 않는다
  • 객체에 임시로 어떤 값을 보관하고 싶을 때 사용한다.

 

6.7 @Access

  • JPA가 엔티티에 접근하는 방식을 지정한다.
    • 필드 접근 : AccessType.FIELD
    • 프로퍼티 접근 : AccessType.PROPERTY
  • 지정하지 않으면 @Id의 위치를 기준으로 접근 방식이 설정됨