⑥. 고급 매핑 - 상속관계와 MappedSuperclass
이 포스트 시리즈는 inflearn의 ‘‘자바 ORM 표준 JPA 프로그래밍 - 기본편 : 김영한’’ 강의와 개인적인 추가학습을 정리한 내용입니다.
6. 고급 매핑 - 상속관계와 MappedSuperclass
1) 상속관계 매핑
- 객체는 상속관계가 있지만, 데이터베이스 테이블은 상속관계가 없음(기본적으로)
- 슈퍼타입 - 서브타입 관계가 객체 상속과 유사하기 때문에 이를 활용하여 매핑을 함.
1. 조인전략(@Inheritance(strategy = InheritanceType.JOINED)
)
-
Item.java
@Entity @Inheritance(strategy = InheritanceType.JOINED) public class Item { @Id @GeneratedValue private Long id; private String name; private int price; }
-
Album.java
@Entity public class Album extends Item { private String artist; }
-
Movie.java
@Entity public class Movie extends Item { private String director; private String actor; }
-
Book.java
@Entity public class Book extends Item { private String author; private String isbn; }
-
객체 패러다임과 잘 맞고 테이블을 정규화 할 수 있음.
-
저장 시 - Insert 쿼리가 2번 호출됨. 상속하는 테이블과 상속받는 테이블에 각각 저장해야 하기 때문. (각 테이블의 id는 PK-FK값으로 동일하게 매핑되고, 나머지 정보는 필드가 있는 테이블에 넣어야 하기 때문.)
-
조회 시 - 조인을 사용.
-
두 번째 전략인 단일테이블에 비해서 테이블을 많이 사용하기 때문에 나타나는 단점이 있음. (결국 Trade-off 관계임)
2. 단일 테이블 전략(@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
)
-
테이블을 하나만 만들고 테이블 내에서 DTYPE으로 구분하는 것.
-
Item.java
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 변하는 부분 @DiscriminatorColumn(name = "DTYPE") // DTYPE이 기본값. ITEM 테이블에 DTYPE 컬럼이 추가되며, 이 컬럼에 자식엔티티명이 들어가서 구분지음. public class Item { @Id @GeneratedValue private Long id; private String name; private int price; }
-
Album.java
@Entity public class Album extends Item { private String artist; }
-
Movie.java
@Entity public class Movie extends Item { private String director; private String actor; }
-
Book.java
@Entity public class Book extends Item { private String author; private String isbn; }
-
저장 및 조회에서 다른 테이블을 사용할 필요가 없음.
-
하나에 뭉쳐서 쓰기 때문에 테이블 크기가 커질 수 있음.
-
단, 자식 엔티티가 매핑한 컬럼은 null이 허용될 수 밖에 없음.
-
@DiscriminatorColumn
&@DiscriminatorValue("대체할 이름")
- 단일테이블 전략 사용 시, 한 테이블에 정보가 다 들어가기 떄문에 어떤 자식엔티티인지 구분할 컬럼이 필요함.
- DTYPE 컬럼을 사용하여 구분. **=> 조인전략도 결국 있는게 좋음. 조인전략 테이블을 까보면 ITEM 테이블 값만 보면 어떤 자식 엔티티 값인지 구분이 안됨. *
- 부모엔티티에
@DiscriminatorColumn
, DTYPE이 아니라 다른 컬럼명도 (name = “컬럼명”) 사용 가능. - DTYPE 값을 다른걸 사용하고 싶다면 자식엔티티에
@DiscriminatorValue("대체할 이름")
3. 구현 클래스마다 테이블 전략(@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
)
- 상속 테이블이 없음.
- 각자 도생.
- 조회 시 UNION 쿼리 필요. (자식 테이블을 다 뒤져봐야 함.)
- 개발자와 DB담당자 모두 선호하지 않음!!
4. 그럼 어떤 전략을 써야 하나?
- 기본적으로 조인전략. 정석적이며 객체 패러다임과 잘 맞기 때문.
- 조인전략 - 단일 테이블 전략의 Trade-off를 생각하여 선택.
- 확장 가능성이 낮고 단순한 편이면 단일 테이블 전략을 가져가는 것이 단순하고 좋음.
- 비즈니스적으로 굉장히 중요한 테이블이며, 확장 가능성이 있따면 조인전략을 사용하는 것이 추후 유연한 확장에 용이함.
- 다만, 현실세계처럼 복잡해지기 때문에 데이터가 많아질수록 관리 및 유지보수가 어려워질 수 있음. 인지의 범위를 넘어서는 경우가 생길 수 있음.
- 때문에 처음에는 조인전략으로 가되, 데이터가 많아져서 조인전략의 장점보다 단점이 커지는 시점이 되는 경우 시스템을 개편하고 설계를 변경하는 등의 방식으로 유지보수를 할 것을 추천.
2) MappedSuperclass
- 공통 매핑정보가 필요할 때 사용. (마치 Java의 인터페이스와 비슷)
- 예를들어, 우리 어플리케이션에는 모든 테이블에 항상 있어야 하는 정보들이 있다면 (createDt, createBy, modifiedDt, modifiedBy 등등) 이러한 속성만 상속받아서 사용 가능.
- 따라서 추상클래스로 만드는 것이 좋음.
- 엔티티가 아님. 테이블도 생성이 안되기 떄문에, 해당 클래스를 사용하여 조회, 저장 등은 불가능.
-
BaseEntity.java
@MappedSuperclass public abstract class BaseEntity { @Id @GeneratedValue private Long id; private String name; // 아래는 이런식의 정보들이 보통 MappedSuperclass에 많이 활용된다는 예시 private String createBy; private LocalDateTime createDt; private String modifiedBy; private LocalDateTime modifiedDt; }
-
Member.java
@Entity public class Member extends BaseEntity { private String email; }
-
Seller.java
@Entity public class Seller extends BaseEntity { private String shopName; }
3) 연관관계 기본 매핑 예시
(Getter, Setter 코드는 생략)
- Item의 자식클래스, 모든 클래스에 등록일과 수정일 추가!
- Item.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 단일 테이블 전략
@DiscriminatorColumn // DTYPE 사용
public class Item extends BaseEntity { // MappedSuperclass 사용
@Id
@GeneratedValue
@Column(name="ITEM_ID")
private Long id;
@OneToMany
@JoinColumn(name = "CATEGORY_ID")
private List<Category> categories = new ArrayList<>();
private String name;
private int price;
private int stockQuantity;
}
- Album.java
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Album extends Item {
private String artist;
private String etc;
}
- Book.java
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Book extends Item {
private String author;
private String isbn;
}
- Movie.java
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
public class Movie extends Item {
private String director;
private String actor;
}
- BaseEntity.java (MappedSuperclass)
import java.time.LocalDateTime;
@MappedSuperclass
public abstract class BaseEntity {
private String createBy;
private LocalDateTime createDt;
private String modifiedBy;
private LocalDateTime modifiedDt;
}
마지막 수정일시: 2022-09-02 13:53
댓글남기기