JPA

[JPA] 12. 상속 관계 매핑

inuma 2021. 1. 11. 23:01
프로젝트 git url github.com/rtef23/JpaStudy
필요 1. docker
2. docker-compose
프로젝트 정보 mysql : 5.7 - docker image
java : 1.8

 

상속 관계 매핑

  • 관계형 데이터베이스에서는 상속 관계는 없다.(슈퍼 타입 - 서브 타입 관계 모델링이 상속과 유사)

 

조인 전략

  • 공통화할 수 있는 부분(Item - name, price)은 슈퍼 타입으로 분할하는 방식
@Entity
@Table(name = "ITEM")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public class Item {
  @Id
  @GeneratedValue
  @Column(name = "item_id")
  private Long id;

  private String name;
  private int price;
  
  ...
}

@Entity
@Table(name = "ALBUM")
@DiscriminatorValue("Album2")
public class Album extends Item {
  private String artist;
  
  ...
}

@Entity
@Table(name = "BOOK")
public class Book extends Item {
  private String author;
  private String isbn;
  
  ...
}

@Entity
@Table(name = "MOVIE")
public class Movie extends Item {
  private String director;
  private String actor;
  
  ...
}
  • @Inheritance(strategy = InheritanceType.JOINED)
    • ; Join 테이블 전략을 사용
  • @DiscriminatorColumn
    • 자식 테이블을 구분하는 값을 사용한다는 것을 명시
    • 컬럼명의 기본 값으로는 DTYPE으로 정의되어 있음
    • 컬럼에 들어갈 값을 따로 설정해주지 않는 경우, 기본적으로는 자식 엔티티 클래스 명이 들어가게 된다.
  • @DiscriminatorValue
    • 부모 엔티티에서 자식 테이블을 구분하는 컬럼에 들어갈 값을 표시하는 어노테이션
  • 장점
    • 테이블 정규화
    • 외래키 참조 무결성 제약 조건 활용 가능
    • 저장 공간 효율화
  • 단점
    • 조회시 조인을 많이 사용
    • 조회 쿼리 복잡
    • 데이터 수정시 Insert/Update 2번 호출(각 테이블에 대해서)

 

단일 테이블 전략

  • 단일 테이블에 모든 타입에서 별도로 필요한 값을 하나의 테이블에 모으는 방식
  • JPA에서 상속을 지원하는 기본 매핑 전략
@Entity
@Table(name = "ITEM")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
public class Item {
  @Id
  @GeneratedValue
  @Column(name = "item_id")
  private Long id;

  private String name;
  private int price;
  
  ...
}

@Entity
@DiscriminatorValue("Album2")
public class Album extends Item {
  private String artist;
  
  ...
}

@Entity
public class Book extends Item {
  private String author;
  private String isbn;
  
  ...
}

@Entity
public class Movie extends Item {
  private String director;
  private String actor;
  
  ...
}
  • @DiscriminatorColumn 어노테이션 필수
  • @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    • ; 단일 테이블 전략을 사용
  • @DiscriminatorColumn
    • 자식 테이블을 구분하는 값을 사용한다는 것을 명시
    • 컬럼명의 기본 값으로는 DTYPE으로 정의되어 있음
    • 컬럼에 들어갈 값을 따로 설정해주지 않는 경우, 기본적으로는 자식 엔티티 클래스 명이 들어가게 된다.
  • @DiscriminatorValue
    • 부모 엔티티에서 자식 테이블을 구분하는 컬럼에 들어갈 값을 표시하는 어노테이션
  • 장점
    • 조회시 조인이 필요 없음
    • 조회쿼리가 단순
  • 단점
    • 자식 엔티티에서 사용하지 않는 컬럼에 대해서 null 허용
    • 테이블에 데이터가 많이 쌓이게 되는 경우, 조회 성능이 느려질 수 있다.

 

구현 클래스별 테이블 분할

  • 각 타입별 새로운 테이블 생성
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
  @Id
  @GeneratedValue
  @Column(name = "item_id")
  private Long id;
  
  ...
}

@Entity
public class Album extends Item {
  private String artist;

  ...
}

@Entity
public class Book extends Item {
  private String author;
  private String isbn;
  
  ...
}

@Entity
public class Movie extends Item {
  private String director;
  private String actor;
  
  ...
}
  • @DiscriminatorColumn, @DiscriminatorValue 어노테이션이 무의미
  • @InheritanceType.TABLE_PER_CLASS
    • ; 구현 클래스별 테이블 전략을 사용
  • 장점
    • 서브 타입을 명확하게 구분하여 처리할 때 효과적
    • not null 제약 조건 사용 가능
  • 단점
    • 조회시 UNION ALL을 사용하여 조회하게 됨
    • 자식 테이블을 통합해서 쿼리하기 어려움