JPA는 DB의 슈퍼타입/서브타입 과 같은 어떠한 논리적 기법을 어떤 3가지 방법으로 매핑을 하던 모든 매핑을 지원한다.
: 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑하는것
: 객체의 상속, 구조, DB의 슈퍼타입 서브타입 관계를 매핑한다.
- 객체는 상속관계가 있지만, DB는 상속관계가 없다.
- 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사하다.
-
조인 전략 → 각각 테이블로 변환
-
단일 테이블 전략 → 통합 테이블로 변환
-
구현 클래스마다 테이블 전략 → 서브타입 테이블로 변환
: 각각 테이블로 변환한다.
굉장히 정규화된 방법이다. 설계를 기본적으로 깔고 들어가야 한다.
-
@Inheritance(strategy = InheritanceType.JOINED)
-
슈퍼타입 테이블의 "기본키"를 서브타입 테이블의 "기본키"겸 "외래키"로 둔다.
-
그후 상위 테이블은 조인할 테이터를 구분할 수 있는 구분 컬럼을 둔다.
- 테이블을 정규화 할 수 있다
- FK 참조 무결성 제약조건 활용가능하다
- 저장공간이 효율화 된다.
- 조회시 조인을 많이 사용한다. → 성능 저하
근데 그렇게 크게 문제가 될건 아니다. - 김영한
- 조회 쿼리가 복잡하다.
- 데이터 저장시
INSERT query
를 2번 호출한다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn // 무슨타입인지 알려주는 DTYPE 컬럼추가
public abstract class Item{
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("A") //이렇게 DTYPE을 지정 할 수 있다.
public class Album extends Item{
private String artist;
}
@Entity
public class Movie extends Item{
private String director;
private String actor;
}
@Entity
public class Book extends Item{
private String author;
private String isbn;
}
: 통합 테이블로 변환한다. → 걍 다 합쳐버린다.
테이블은 단순하지만 객체지향적으로 상속하게 되어있을수 있다.
- 성능적으로 좋다. 쿼리도 적게 나간다.
- 테이블이 단일 테이블이라 내가 무슨 타입인지 모르므로 기본으로 DTYPE이 들어간다.
조인 전략은 어쨌든 DTYPE없어도 내가 무엇인지 찾을 수 있지만...
- 일반적으로 조회 성능이 빠르다. → 조인이 필요 없으므로
- 조회 쿼리가 단순하다.
- 데이터 무결성에 문제가 있다. → 자식 엔티티가 매핑한 컬럼은 모두 null을 허용한다.
- 조회 성능이 오히려 느려질 수 있다. → 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있기 때문이다.
이 정도 임계점을 넘기가 힘들다.
그냥 상위 Entity에
Inheritance(strategy = InheritanceType.SINGLE_TABLE)
를 해주면 된다.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
//@DiscriminatorColumn // 이거 없어도 DTYPE이 넣어진다. 필수적으로 생성된다.
public abstract class Item{
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
: 서브타입 테이블로 변환한다. → 중복되어도 그대로 사용한다.
이 전략은 DB 설계자와 ORM 전문가 둘 다 추천하지 않는다!
너무 비효율적이다. 모든 테이블을 다 찾아야된다. 이건 쓰면 안된다!
- 중간의 아이템을 만들지 않고 중복되는 컬럼을 각각의 테이블에 넣는다.
- 서브 타입을 명확하게 구분해서 처리할 때 효과적
NotNull
제약조건을 사용할 수 있다.
- 여러 자식 테이블을 함께 조회할 때 성능이 느리다. →
UNION QUERY
를 날려야 한다. - 자식 테이블을 통합해서 쿼리하기 어렵다 → 변경이라는 관점에서 보면 엄청 안좋다.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_TER_CLASS)
//@DiscriminatorColumn 의미가 없다. 테이블 자체가 다르다.
public abstract class Item{
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
: 상속 관계 매핑시 부모 클래스에서 자식 클래스를 구분할 컬럼명이다.
@DiscriminatorColumn
DTYPE
의 기본값은 각 자식의 클래스명이다.@DiscriminatorValue("사용자지정값")
처럼 자식테이블에 지정해 줄 수 있다.
DTYPE 필요한 이유
- 객체에서 봤을때는 무엇을 조인해야되는지 알 수 있다.
- 하지만 DB에 쿼리를 날렸을 때 어떠한 테이블로 인하여 값이 들어왔는지 모른다.
(Album? Movie? Book?) DTYPE
은 운영상 있는게 좋다.