상속 관계 매핑
- ORM에서 이야기하는 상속 관계 매핑은 객체의 상속 구조와 데이터베이스의 슈퍼타입 서브타입 관계를 매핑하는 것이다.
- 슈퍼타입 서브타입 논리 모델을 실제 물리 모델인 테이블로 구현할 때는 3가지 방법을 선택할 수 있다.
=> 각각의 테이블로 변환, 통합 테이블로 변환, 서브타입 테이블로 변환
조인 전략
- 엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본 키를 받아서 기본 키 + 외래 키로 사용하는 전략
- 조회할 때 조인을 자주 사용한다.
- 객체는 타입으로 구분할 수 있지만 테이블은 타입의 개념이 없으므로 타입을 구분하는 컬럼을 추가해야 한다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
...
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
...
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
private String director;
private String actor;
...
}
@Entity
@DiscriminatorValue("B")
@PrimaryKeyJoinColumn(name = "BOOK_ID") // ID 재정의
public class Book extends Item {
private String author;
private String isbn;
...
}
- 자식 테이블의 기본 키 컬럼명을 변경하고 싶으면 @PrimaryKeyJoinColumn을 사용하면 된다.
장점
- 테이블이 정규화된다.
- 외래 키 참조 무결성 제약 조건을 활용할 수 있다.
- 저장 공간을 효율적으로 사용한다.
단점
- 조회할 때 조인이 많이 사용되므로 성능이 저하될 수 있다.
- 조회 쿼리가 복잡하다.
- 데이터를 등록할 INSERT SQL을 두 번 실행한다.
특징
- JPA 표준 명세는 구분 컬럼을 사용하도록 하지만 하이버네이트를 포함한 몇몇 구현체는 구분 컬럼(@DiscriminatorColumn) 없이도 동작한다.
단일 테이블 전략
- 테이블을 하나만 사용한다.
- 구분 컬럼으로 어떤 자식 데이터가 저장되었는지 구분한다.
- 조인을 사용하지 않으므로 일반적으로 가장 빠르다.
- 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
...
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
...
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
private String director;
private String actor;
...
}
@Entity
@DiscriminatorValue("B")
public class Book extends Item {
private String author;
private String isbn;
...
}
장점
- 조인이 필요 없으므로 일반적으로 조회 성능이 빠르다.
- 조회 쿼리가 단순하다.
단점
- 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다.
- 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다. => 상황에 따라 조회 성능이 오히려 느려질 수 있다.
특징
- 구분 컬럼을 꼭 사용해야 한다.(@DiscriminatorColumn)
- @ DiscriminatorValue를 지정하지 않으면 기본으로 엔티티 이름을 사용한다.
구현 클래스마다 테이블 전략
- 자식 엔티티마다 테이블을 만든다. 그리고 자식 테이블 각각에 필요한 컬럼이 모두 있다.
- 일반적으로 추천하지 않는 전략이다.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
...
}
@Entity
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;
...
}
장점
- 서브 타입을 구분해서 처리할 때 효과적이다.
- not null 제약 조건을 사용할 수 있다.
단점
- 여러 자식 테이블을 함께 조회할 때 성능이 느리다(SQL에 UNION을 사용해야 한다).
- 자식 테이블을 통합해서 쿼리하기 어렵다.
특징
- 구분 컬럼을 사용하지 않는다.
'공부 기록 > Java' 카테고리의 다른 글
[이펙티브 자바 3/E] 아이템20 - 추상 클래스보다는 인터페이스를 우선하라 (1) | 2023.11.13 |
---|---|
[이펙티브 자바 3/E] 아이템19 - 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (1) | 2023.11.11 |
[JPA] 6장 - 다양한 연관관계 매핑(2) - 일대일, 다대다 (0) | 2023.09.15 |
[이펙티브 자바 3/E] 아이템18 - 상속보다는 컴포지션을 사용하라 (0) | 2023.09.08 |
[이펙티브 자바 3/E] 아이템17 - 변경 가능성을 최소화하라 (0) | 2023.09.07 |