BACK/JPA

[JPA] TIL 8일차 : JPA 고급 매핑 - 상속 관계 매핑

연듀 2024. 4. 4. 21:05

 

 

관계형 데이터베이스는 상속 관계가 없다.

대신 슈퍼타입 서브타입이라는 모델링 기법이 객체 상속과 유사하다. 

 

객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑해 상속관계를 매핑한다.

 

 

슈퍼 타입 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법

- 각각 테이블로 변환 : 조인 전략

- 통합 테이블로 변환 : 단일 테이블 전략

- 서브타입 테이블로 변환: 구현 클래스마다 테이블 전략

 

 

조인 전략

 

필요한 테이블을 조인해 가져옴

 

 

@Inheritance(strategy = InheritanceType.JOINED)

 

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn // dtype 컬럼이 생기고 기본 값으로는 엔티티 명이 된다.
public class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int price;
@Entity
@DiscriminatorValue("A") // 기본은 엔티티 이름
public class Album extends Item{
    private String artist;
}
@Entity
@DiscriminatorValue("B")
public class Book extends Item{
    private String author;
    private String isbn;
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item{
    private String director;
    private String actor;

 

장점:

테이블이 정규화 되어 있다.

→ 저장 공간 효율화

외래 키 참조 무결성 제약 조건을 활용할 수 있다.

 

단점: 

조회할 때 조인을 많이 사용해(쿼리 복잡) 성능 저하될 수 있다. (많이 저하되진 않음)

데이터 저장시 두번 insert문이 들어간다.

 

조인전략이 정석이다.

 

 

단일 테이블 전략

 

 

*@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

 

 

기본 값은 단일 테이블 전략

PK를 하나만 두고 모든 자식 객체들의 필드들을 합쳐 하나의 테이블로 만든다.

이 때 Dtype이라는 컬럼명으로 어떤 테이블인지 구분한다. 

 

 

 

insert문도 쿼리 한번으로 들어간다.

@DiscriminatorColumn이 없어도 필수로 테이블에 DTYPE 컬럼이 들어간다.

 

장점: 

조인이 필요 없어 조회 성능이 빠르다.

한 테이블만 조회하면 되므로 조회 쿼리가 단순하다.

 

단점: 

자식 엔티티가 매핑한 컬럼은 모두 null을 허용한다 → 데이터 무결성 입장에서는 애매

단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있어서 상황에 따라서는 조인 테이블과 비교해 성능이 느려질 수 있다.

 

 

 

구현 클래스마다 테이블 전략

 

 

각각의 테이블에 슈퍼타입의 필드들을 가지고 있음

이 전략은 데이터베이스 설계자와 ORM 전문가 둘다 추천X 

 

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
// @DiscriminatorColumn // 필요 없다. 
public abstract class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int price;
..

 

 

ITEM 클래스를 추상클래스로 만든다.

ITEM의 필드들을 가지고 있는 ALBUM, MOVIE, BOOK 테이블만 생성된다.

만약 Item Id만 알고 찾으려 할 때, 세개의 테이블 모두 다 union 해서 찾아야 하기 때문에 비효율적이다.

쓰면 안되는 전략이다.

 

장점: 서브 타입을 명확하게 구분해서 처리할 때 효과적이고, not null 제약 조건을 사용할 수 있다.

단점: 하지만 여러 자식 테이블을 함께 조회할 때 성능이 느리다(union sql 필요)

 

 

 

매핑 정보 상속

 

@Mapped Superclass

  • 공통의 매핑 정보가 필요할 때 사용

공통된 속성들을 모든 클래스에서 사용하고 싶을때,

@MappedSuperclass가 붙은 새로운 클래스를 하나 만들어 이 클래스를 상속받는다.

 

*참고) JPA의 @Entity 클래스는 @Entity나 @MappedSuperclass가 붙은 클래스 만을 상속받을 수 있다.

 

@MappedSuperclass
public abstract class BaseEntity {
    @Column(name="INSERT_MEMBER")
    private String createdBy;
    private LocalDateTime createdDate;

    @Column(name="UPDATE_MEMBER")
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;
...

 

 

테이블과 관계없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모으는 역할을 한다. 

 

상속관계 매핑이 아니다.

엔티티가 아니기 때문에 테이블과 매핑이 안된다.

부모 클래스를 상속받는 자식 클래스에 매핑 정보만 제공한다.

조회나 검색이 불가능하다.(em.find(BaseEntity) 불가) 

직접 생성해서 사용할 일이 없으니 추상 클래스로 하는 것을 권장한다.

 

 

 

 

 

인프런 자바 ORM 표준 JPA 프로그래밍 - 기본편을 수강하고 정리한 글입니다.

https://www.inflearn.com/course/ORM-JPA-Basic