course/inflearn

[JPA 프로그래밍 기본편] 고급 매핑

hjkim0502 2022. 9. 6. 23:43

상속관계 매핑: 객체의 상속 관계와 DB의 슈퍼타입, 서브타입 관계 매핑

  • 객체는 상속관계 존재

  • RDB는 상속관계 X
    • 슈퍼타입, 서브타입 관계라는 유사한 논리 모델링 기법 존재
    • 이 논리 모델을 물리 모델로 구현하는 방법
      • 1. 조인 전략
      • 2. 단일 테이블 전략
      • 3. 구현 클래스마다 테이블 전략
    • 객체 입장에서는 아무 변화가 없고, DB설계를 어떻게 할 것이냐 결정하는 것
      • JPA는 세가지 방법 모두 지원 (기본 설정: 단일 테이블 전략)
// Item class
@Entity
public class Item {

    @Id @GeneratedValue
    private Long id;

    private String name;
    private int price;
    
// Album class
@Entity
public class Album extends Item {

    private String artist;
}

// Movie class
@Entity
public class Movie extends Item {

    private String director;
    private String actor;
}

// Book class
@Entity
public class Book extends Item {

    private String author;
    private String isbn;
}

 

1. 조인 전략: 각각 테이블로 변환

  • 저장 시 각각의 필드에 매핑된 컬럼이 속한 테이블에 맞게 저장 (INSERT 두번)
  • 조회 시 해당하는 두 테이블을 조인하여 조회
    • DTYPE으로 ALBUM인지 MOVIE인지 BOOK인지 구별 (사용 권장)
    • DTYPE 사용하면 ITEM 테이블만 확인해도 어떤 상품 종류인지 확인 가능
    • 조인 전략에서는 DTYPE 활성화 하지 않아도 작동하지만 나머지 전략에는 필수
// Item class
@Entity
@Inheritance(strategy = InheritanceType.JOINED) // 조인 전략
@DiscriminatorColumn // DTYPE 사용
// @DiscriminatorColumn(name="DIS_TYPE")
public class Item {

// Album class
@Entity
@DiscriminatorValue("A") // DTYPE 컬럼에 들어갈 이름 (기본값: 엔티티 이름)
public class Album extends Item {

    // id 생략하면 부모의 id(ITEM_ID)가 id가 됨
    //@Id @GeneratedValue
    //private Long id;

 

SELECT * FROM ITEM;

DTYPE ID NAME PRICE
A 1 n 100

 

2. 단일 테이블 전략: 통합 테이블로 변환

  • 한 테이블에 합치고 DTYPE으로 구분
    • 테이블이 커지면 성능 저하 우려 (흔하지 않은 경우임)
  • 저장 시 INSERT 한번에, 조회시 조인 없이 SELECT 한번 -> 좋은 성능
  • 자식 엔티티가 매핑한 컬럼은 모두 null 허용
    • 위 경우 NAME, PRICE 제외하고 모두 null 허용해주어야 하므로 데이터 무결성의 측면에서 단점이 될 수 있다
  • @DiscriminatorColumn 없어도 자동으로 DTYPE 활성화
// Item class
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 생략 가능
@DiscriminatorColumn // 생략 가능
public class Item {

 

3. 구현 클래스마다 테이블 전략: 서브타입 테이블로 변환 (사용하지 말 것!)

  • ITEM 테이블 생성되지 않고 ITEM의 컬럼들을 서브타입 테이블에 중복되게 저장 (여기선 NAME, PRICE 컬럼)
  • 저장 시 INSERT 한번에, 조회시 조인 없이 SELECT 한번
    • 대신 ITEM_ID로 조회한다면 세 서브타입 테이블에 SELECT 다 날려서 찾아야 함 (비효율적)
  • 연결되어 있지 않기 때문에 통합해서 쿼리하기 어렵고, 시스템에 변경이 생겼을 때 많은 부분을 고쳐야 함
// Item class
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
//@DiscriminatorColumn // 필요없음
public abstract class Item { // 추상 클래스로 해야 맞음

 

기본적으로 조인 전략으로 가져가되,
상황이 단순하고, 확장 가능성도 적다면 단일 테이블 전략 사용

 

@MappedBySuperclass

  • 공통 매핑 정보가 필요할 때 사용 (예: id, name)
// BaseEntity class
@MappedSuperclass
public abstract class BaseEntity { // 추상 클래스 권장

    private LocalDateTime createdAt;
    private LocalDateTime modifiedAt;
}

// Member class
@Entity
public class Member extends BaseEntity {

// Team class
@Entity
public class Team extends BaseEntity {
  • 상속 관계 매핑 x
  • BaseEntity는 테이블로 생성되지 않음, 조회 및 검색 불가
  • 참고: @Entity가 붙은 클래스는 @Entity나 @MappedSuperclass가 붙은 클래스만 상속받을 수 있음

출처: 김영한님 JPA 프로그래밍 입문