오브젝트의 상속관계를 RDB의 테이블로 표현하는 JPA의 기능이다. 엄밀하게 말하자면 상속관계가 존재하지 않는 RDB와 상속관계가 존재하는 자바코드를 서로 맵핑하는 것을 목적으로 한다.
논리모델의 상속관계는 오브젝트 모델로도 표현이 가능하다.하지만 RDB에서는 상속이 불가능 하므로 논리모델 에서의 슈퍼타입 - 서브타입을 구현할 방법이 필요하다.
자바 코드단은 위의 논리모델을 구현하기 용이하다 ITEM class를 구현하고 각 자식클래스에서 상속해주면 끝난다. 하지만 RDB에서는 위와같은 방법이 불가능하기 때문에 전략을 설정해줘야한다.
전략
- @Inheritance(strategy=InheritanceType.XXXX)
- @DiscriminatorColumn(name="DTYPE")
- @DiscriminatorValue("NAME")
Inheritance 어노테이션의 전략은 크게 3가지다.
default 전략은 SINGLE_TABLE 이다.
@Entity
@Data
// 전략 설정 어노테이션
@Inheritance(strategy = InheritanceType.XXXX)
public class Item {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
@Entity
@Data
public class Book extends Item{ // Item 상속
private String author;
private String isbn;
}
@Entity
@Data
public class Movie extends Item{
private String director;
private String actor;
}
슈퍼 클래스인 Item에 @Inheritance 어노테이션을 적용해주고 전략을 설정해준다. InheritanceType에 적용할 전략을 선언한다.각 서브클래스는 슈퍼클래스인 Item을 상속받아 사용한다.(getter setter 쓰기 귀찮아서 lombok @Data 어노테이션을 사용했다. 코틀린은 getter setter를 내부적으로 생성해준다. 확실히 자바보다 코틀린의 생산성이 높은 이유가 있다.)
그러면 이제 각 전략을 알아보자
SINGLE_TABLE
- @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
- 단일 테이블 전략
- 각 서브 클래스의 모든 필드를 한 테이블에 생성한다
- 해당 서비스가 단순하고 굳이 조인전략이 필요 없다고 판단될때 쓰면된다.
JOINED
- @Inheritance(strategy=InheritanceType.JOINED)
- 정규화된 방법
- ITEM,BOOK,MOVIE,ALBUM 각각의 테이블이 생성되고 각 엔티티를 맵핑할때 해당 엔티티와 ITEM 엔티티가 맵핑되어 저장된다.
- 서브 클래스에 대응되는 테이블은 ITEM의 id를 PK,FK로 지정한다.(당연..)
- DTYPE은 클래스 이름으로 지정된다(디폴트)
요즘은 DB성능이 워낙 좋아지고 단일 테이블에 비해 성능 차이도 체감할 정도는 아니다 보니 정규화 되어있는 JOINED를 많이 사용하라고 권고하는편.
- @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
- 각 서브 엔티티의 테이블에 Item 엔티티의 필드가 모두 포함 된다.
- 테이블에서 슈퍼 클래스를 없애고 슈퍼클래스의 필드를 서브클래스에 각각 정의한다.
- ITEM은 abstarct로 설정
- 다시말하면, ITEM 테이블은 없고 BOOK,MOVIE,ALBUM만 있는것.
설명을 덧붙이자면 TABLE_PER_CLASS로 전략을 설정하게 되고 조회했을시,
Item item = em.find(Item.class,movie.getId());
와 같은 코드로 조회시 모든 서브 엔티티를 호출하여 UNION하게 되므로 성능이 떨어질 수 밖에 없다.
결론 : TABLE_PER_CLASS는 웬만하면 쓰지말자
해당 어노테이션은 상속개념과는 관계가 없고, 엔티티들이 공통적인 속성을 가질때 공통필드를 BaseEnitiy로 따로 묶어서 관리해줄때 사용한다.
예를들면, 모든 테이블에는 생성시각,생성자,수정시각,수정자와 같은 모든 테이블 에서 공통적으로 포함되어야할 컬럼을 BaseEntitiy로 묶어주고 해당 어노테이션을 사용하여 관리하는것. 다시말하면 맵핑 정보만 상속받는다
@MappedSuperclass
public abstract class BaseEntity {
private LocalDateTime createAt;
private String createBy;
private LocalDateTime lastModifiedAt;
private String modifiedBy;
}