본문 바로가기
JPA

[JPA] 엔티티 매핑

by snow_white 2022. 7. 28.
※ 인프런 강의 김영한님의 「자바 ORM 표준 JPA 프로그래밍」을 학습한 내용을 정리한 글입니다. 

1️⃣ 객체와 테이블 매핑

@Entity

  • @Entity가 붙은 클래스는  JPA가 관리, 엔티티라 한다.
  • JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수
  • 주의
    • 기본 생성자 필수(파라미터가 없는 public 또는 protected 생성자)
    • final 클래스, enum, interface, inner 클래스 사용 X
    • 저장할 필드에 final 사용 X
  • 속성: name
    • JPA에서 사용할 엔티티 이름을 지정한다.
    • 기본값: 클래스 이름을 그대로 사용
    • 같은 클래스 이름이 없으면 가급적 기본값을 사용하도록 한다.
@Entity(name="Member") // 클래스명과 동일
public class Member {
	...
}

 

@Table

  • @Table은 엔티티와 매핑할 테이블을 지정하는 것이다.
  • @Table 속성
    • name
      @Table(name = "MBR")
      매핑할 테이블 이름을 지정한다.
      기본값: 엔티티 이름을 사용
      ex) SELECT * FROM MBR
    • catalog
      데이터베이스 catalog 매핑
    • schema
      데이터베이스 schema 매핑
    • uniqueConstraints(DDL)
      DDL 생성 시에 유니크 제약 조건 생성

 

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

  • DDL을 애플리케이션 실행 시점(loading)에 자동으로 생성한다.
  • 테이블 중심 -> 객체 중심
  • 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성한다.
    Ex) oracle: varchar2, MySQL: varchar 등
  • 이렇게 생성된 DDL은 개발 로컬 장비에서만 사용
  • 생성된 DDL은 운영서버에서는 사용하지 않거나, 적절히 다듬은 후 사용하기를 권장함

XML 설정 파일에서 데이터베이스 스키마 자동 생성 속성 지정하기

<property name="hibernate.hbm2ddl.auto" value="create"/>
옵션 설명
create 기존 테이블 삭제 후 다시 생성 (DROP + CREATE)
create-drop create와 같으나 종료 시점에 테이블 DROP (테스트에서 사용하면 도움 됨)
 update 변경 분만 반영 ( 운영 DB에서는 사용하면 안 됨)
validate 엔티티와 테이블이 정상 매핑되었는지만 확인
none 사용하지 않음

 

DDL 생성 기능

  • 제약 조건 추가 가능 
    @Column(nullable = false, length = 10) : 회원 이름은 필수, 10글자 초과 X
    @Column(unique = true) : DB에 영향을 주는 것, 해당 필드는 unique 함을 의미
  • Unique 제약 조건 추가
@Table(uniqueConstraints = {@UniqueConstraint(name = "NAME_AGE_UNIQUE", columnNames = {"NAME", "AGE"})})
  • DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
    즉, DB에만 영향을 주는 것이지 애플리케이션에 영향을 주는 것이 아니다.
    JPA의 실행 매커니즘에 영향을 주는 것이 아니라 alter table과 같은 스크립트가 실행되는 것을 말한다.
    Cf) insert, update는 Runtime에 영향을 준다.

2️⃣ 필드와 컬럼 매핑

@Column(name="데이터베이스칼럼명") → 컬럼 매핑

@Enumerated(EnumType.STRING) → Enum 타입 매핑

@Temporal(TemporalType.TIMESTAMP) → 날짜 타입 매핑/ TIME, DATE, TIMESTAMP 세 가지로 나뉨

@Lob  → VARCHAR를 넘어서는 큰 값 지정

 

❌ EnumType.ORDINAL 은 사용하지 않는다.

  • EnumType.ORDINAL
    enum 순서를 데이터베이스에 저장 (기본값)
  • EnumType.String
    enum 이름을 데이터베이스에 저장
public enum RoleType{
	USER, ADMIN
}
public enum RoleType{
	GUEST, USER, ADMIN // 맨 앞에 GUEST 추가
}

 

요구 사항에 따라 새로운 Type이 추가될 수 있기 때문에 순서가 변경될 수 있다.

USER(0), ADMIN(1)에서 GUEST가 추가되면 GUEST(0), USER(1), ADMIN(2)가 되므로 USER(0)으로 저장되어 있는 데이터를 수정하기 어려워진다. 즉, GUEST를 enum class 맨 앞에 추가 했을 때 GUEST와 USER 모두가 ‘0’으로 저장되기 때문에 필수처럼 EnumType.String 을 사용한다.

 

3️⃣ 기본 키 매핑

  • 직접 할당 : @Id만 사용
  • 자동 생성(@GeneratedValue)
    • IDENTITY : 데이터베이스에 위임, MySQL
    • SEQUENCE : 데이터베이스 시퀀스 오브젝트 사용, ORACLE
      • @SequenceGenerator 필요
    • TABLE : 키 생성용 테이블 사용, 모든 DB에서 사용
      • @TableGenerator 필요
    • AUTO : 방언에 따라 자동 지정, 기본값

IDENTITY

  • @GeneratedValue(strategy = GenerationType.IDENTITY)
  • 기본 키 생성을 데이터베이스에 위임
  • 즉, id 값을 null로 하면 DB가 알아서 AUTO_INCREMENT 해준다.
    Ex) MySQL, PostgreSQL, SQL Server DB2 등
  • AUTO_INCREMENT는 데이터베이스에 INSERT SQL을 실행한 이후에 ID 값을 알 수 있음
  • IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회
    • JPA는 트랜잭션 commit 시점에 INSERT SQL을 실행하지만 AUTO_INCREMENT의 경우 DB에 INSERT 문을 실행한 이후에야 id 값을 알 수 있다. 영속성 컨텍스트에서 해당 객체가 관리되려면 무조건 PK 값이 있어야 하기 때문에 IDENTITY 전략에서만 예외적으로 em.persist() 시점에 바로 DB에 INSERT 쿼리문을 실행한다.
public class Member {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private String id; 
}

 

SEQUENCE

  • @GeneratedValue(strategy = GenerationType.SEQUNCE)
  • 데이터베이스 Sequence Object를 사용
    DB Sequence는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트
    테이블 마다 시퀀스 오브젝트를 따로 관리하고 싶으면 @SequenceGenerator에 sequenceName 속성을 추가한다.
  • 즉, DB가 자동으로 숫자를 generate 해준다.
    Ex) Oracle, PostgreSQL, DB2, H2 등
@Entity
@SequenceGenerator(
  name = "MEMBER_SEQ_GENERATOR", 
  sequenceName = "MEMBER_SEQ", // 매핑할 데이터베이스 시퀀스 이름 
  initialValue = 1,
  allocationSize = 1)
public class Member {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE,
                  generator = "MEMBER_SEQ_GENERATOR")
  private Long id; 
}
https://gmlwjd9405.github.io/2019/08/12/primary-key-mapping.html

 

TABLE

  • @GeneratedValue(strategy = GenerationType.TABLE)
  • 키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략
  • @TableGenerator 필요
@Entity
@SequenceGenerator(
  name = "MEMBER_SEQ_GENERATOR", 
  table = "MY_SEQUENCES", // 데이터베이스 이름 
  pkColumnValue = "MEMBER_SEQ",
  allocationSize = 1)
public class Member {
  @Id
  @GeneratedValue(strategy = GenerationType.TABLE,
                  generator = "MEMBER_SEQ_GENERATOR")
  private Long id; 
}

 

AUTO

@GeneratedValue(strategy = GenerationType.AUTO)
기본 설정 값
방언에 따라 위의 세 가지 전략을 자동으로 지정한다.

 

기본 키 제약 조건
1. null이 아니다.
2. 유일하다.
3. 변하면 안된다.
미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 그 대신 대리키/대체키를 사용하자.
자연키 (Natural Key) : 비즈니스적으로 의미가 있는 키 Ex) 전화번호, 주민등록번호 등
대리키/대체키 (Generate Value) : 비즈니스적으로 상관없는 키 Ex) Generate Value, 랜덤 값, 유휴 값 등


권장하는 식별자 구성 전략
(Long형) + (대체키) + (적절한 키 생성 전략) 사용

'JPA' 카테고리의 다른 글

[JPA] 연관관계 매핑 - 양방향 연관관계  (0) 2022.08.08
[JPA] 연관관계 매핑 - 단방향 연관관계  (0) 2022.08.07
[JPA] 준영속 상태  (0) 2022.07.18
[JPA] 플러시(Flush)  (0) 2022.07.18
[JPA] 영속성 관리  (0) 2022.07.18

댓글