jpa 상속관계 맵핑

상속관계의 구현

  • 객체에서의 상속과 같은 개념은 관계형 데이터베이스에 존재하지 않는다.
  • 다만, 슈퍼 테이블 개념이 있지만, 이것은 상속관계를 구현하는 방법 중 하나로 사용된다.
  • 논리 모델을 구현 모델(DB설계)로 구현한다.
  • 반대로 객체 입장에서의 설계는 동일(논리모델)하지만 그것의 구현만 차이를 가진다. JPA나 자바 입장에서는 반대로 모든 방식을 지원한다.

상속관계 구현의 전략

  • 조인전략 : 슈퍼 테이블과 자식 테이블을 각각 구현한다.
  • 단일테이블 전략 : 부모와 자식들의 필드를 모두 한 테이블로 한다.
  • 서브타입 테이블로 변환 : 각각의 자식테이블이 부모의 필드를 가진다.

조인 전략

  • JPA와 가장 유사한 모델
  • 자식의 PK는 부모의 FK이기도 하다.
  • 부모 클래스에 대한 조회가 많을 때 장점이 크다. 이 경우 단순하고 깔끔한 코딩이 가능하다. 저장공간을 효율적으로 사용하고 메모리를 적게 쓴다.
  • 다만, 조회할 때 조인을 자주 사용한다. insert 쿼리가 두 번 발생한다. 테이블이 많아서 관리가 다소 복잡하다.
  • JPA의 기본적인 전략으로 생각하고 사용한다.

  • 아래의 코드 중 Inheritance, DiscriminatorColumn, DiscriminatorValue 을 살펴봐야 한다. Inheritance 어너테이션의 전략의 변경만으로 테이블이 자동으로 변경 및 생성된다. 매우 간편하다.
  • DiscriminatorColumn으로 부모 테이블에 해당 자식 테이블이 무엇인지를 명시한다. 기본적으로 칼럼명은 Dtype이며 해당 값은 객체명이나 자식객체의 DiscriminatorValue으로 자유롭게 변경 가능하다.
@Entity

@Inheritance(strategy = InheritanceType.JOINED) 
@DiscriminatorColumn
@Setter
@Getter
public abstract class Item {
    @Id @GeneratedValue
    private Long id;

    private String name;
    private int price;
}

@Entity
public class Album extends Item{

    private String artist;
}

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

@Entity
@DiscriminatorValue("MOV")
@Setter
@Getter
public class Movie extends Item{
    private String direction;
    private String actor;
}

단일테이블 전략

  • jpa의 기본 전략
  • 조인이 필요 없으며 조회가 빠르다.
  • 쿼리가 단순하다.
  • 다만, 자식 객체과 관련하지 않는 다른 자식 칼럼의 경우 null을 허용해야 한다.
  • 단일 테이블에 저장하므로 상황에 따라 조회 성능이 느려진다. 그러나 그런 경우는 크게 없다.
@Entity

@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 기본값, 싱글 테이블 전략
//@DiscriminatorColumn // 생략하더라도 자동적으로 Dtype  칼럼이 생성된다.
@Setter
@Getter
public abstract class Item {
    @Id @GeneratedValue
    private Long id;

    private String name;
    private int price;
}

서브클래스 전략

  • 서브클래스간 묶을 수 있는 방법이 없다.
  • 이로 인하여 union all을 사용해야 하고, 테이블을 통합적으로 사용하기 어렵다. 시스템 변경도 매우 어렵다. 사실상 사용하지 않는다.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 기본값, 싱글 테이블 전략
@Setter
@Getter
public abstract class Item {
    @Id @GeneratedValue
    private Long id;

    private String name;
    private int price;
}

final Item item = em.find(Item.class, movie.getId()); // union all

정리

  • 조인테이블을 기본으로 가져 간다. 필요 시 단일테이블전략을 사용할 수 있다.
  • 단순하고 확장 가능성이 많지 않다고 보일 경우 단일테이블전략을 사용한다.