상속 관계 매핑

신상현·2021년 4월 27일
1

Spring Boot와 JPA

목록 보기
13/16

DB에서의 상속의 표현

  • DB에는 객체 관계에서의 상속 개념이 없다. 대신에Super-Type Sub-Type Relationship 이라는 모델링 기법이 유사하다.
  • ORM 기술에서 말하는 상속 관계 매핑이란, 객체의 상속 구조와 Super-Type Sub-Type Relationship을 매핑하는 것이다.
  • Super-Type Sub-Type Relationship 의 논리 모델을 실제 물리 모델인 테이블로 나타내는 방법에는 3 가지 방법이 있다.

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

각각의 객체를 모두 테이블로 만들고, 조회할 때는 조인을 활용한다.

특징

  • 자식 테이블들은 부모 테이블의 기본 키를 받아서 기본 키 + 외래 키로 삼는다.
  • 따라서 조회할 때, 조인을 많이 활용하게 된다.
  • 객체는 타입에 따라 구분하지만, 테이블의 데이터에는 타입 구분이 없다.
    따라서, DB의 부모 테이블에는 타입을 구분하는 컬럼(DTYPE)을 추가해야 한다.

장단점

  • 장점
    • 테이블이 정규화 되고, 외래 키 참조 무결성 제약 조건을 활용할 수 있다.
    • 저장 공간을 효율적으로 사용한다.
  • 단점
    • 조회할 때 조인을 많이 사용하므로, 쿼리가 복잡해지고 성능이 저하될 수 있다.
    • 데이터를 등록할 때 INSERT SQL이 2번 실행된다.

사용법

  • @Inheritance
    상속 매핑을 할 때 부모 클래스에 어떤 전략을 사용할 것인지 지정해야 한다.

  • @DiscriminatorColumn
    부모 클래스가 매핑된 테이블에서 자식을 구분하기 위해 사용한다.
    name 속성은 DTYPE이 기본 값으로 지정되어 있다.

  • @DiscriminatorValue
    엔티티를 저장할 때, 부모 클래스를 매핑한 테이블의 구분 컬럼에 들어갈 값을 지정한다.

  • @PrimaryKeyJoinColumn
    조인 전략은 자식 테이블들의 기본 키 컬럼명을 부모 테이블과 똑같이 매핑한다.
    만약, 자식 테이블의 컬럼명을 변경하고 싶으면 name 속성에 value를 지정한다.

부모 클래스 - Item 클래스

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DicriminatorColumn(name = "DTYPE")
public abstract class Item {
    
    @Id
    @GeneratedValue
    @Column (name = "ITEM_ID")
    private Long id;
    
    private String name;
    private int price;
}

자식 클래스 - Album, Movie, Book 클래스

@Entity
@DicriminatorValue("A")
public class Album extends Item {
    
    private String artist;
    ...
}


@Entity
@DicriminatorValue("M")
public class Movie extends Item {
    
    private String director;
    private String actor;
    ...
}


@Entity
@DiscriminatorValue("B")
@PrimaryKeyJoinColumn(name = "BOOK_ID")
public class Book extends Item {
    
    private String author;
    private String isbn;
    
}

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

각각의 객체를 테이블을 하나만 사용해서 통합한다.

특징

  • 1 개의 테이블만을 사용한다. 따라서, 자식들을 구분하기 위해서
    DB에서 구분컬럼(DTYPE)을 사용해야한다.

    즉, @DiscriminatorColumn 을 꼭 설정해야 한다.
  • 1 개의 테이블만을 사용하기 때문에 조인이 일어나지 않고 일반적으로 가장 빠르다.
  • 자식 컬럼들을 다 가지고 있어야하기 때문에 쓰이지 않는 컬럼은 null로 만들어야한다. 따라서, 자식 컬럼들이 모두 nullable해야한다
  • @DisCrimivatorValue를 설정하지않으면, 엔티티 이름을 기본 값으로 사용한다.

장단점

  • 장점
    • 조인이 없어서 빠르다.
    • 조회 쿼리가 단순해진다.
  • 단점
    • 자식 컬럼들을 모두 nullable 하게 해야한다.
    • 자식이 많아지면, 테이블이 커지고, 성능이 오히려 저하될 수도 있다.

사용법

  • @DisCriminatorValue
    • 자식 타입을 구분할 수 있도록 구분 컬럼을 꼭 설정해야 한다.
    • 값을 지정하지 않으면, 기본설정으로 엔티티 이름을 구분 값으로 지정한다.

부모 클래스 - Item 클래스

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DisCriminatorColumn(name = "DTYPE")
public abstract class Item {
	
    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    private int price;
}

자식 클래스 - Album, Movie, Book 클래스

@Entity
@DiscriminatorValue("A")
public class Album extends Item {
	...	
}

@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
	...	
}

@Entity
@DiscriminatorValue("B")
public class Book extends Item {
	...	
}

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

자식 엔티티마다 하나의 테이블을 만든다.

특징

  • 일반적으로 추천하지 않는다.
  • 구분 컬럼을 사용하지 않는다.

장단점

  • 장점
    • 서브 타입을 구분해서 처리할 때 효과적이다.
    • not null 제약 조건을 사용할 수 있다.
  • 단점
    • 여러 자식 테이블을 혼합해서 조회할 때 느리다.
    • 자식 테이블을 통합해서 쿼리하기 어렵다.

사용법

부모 클래스 - Item 클래스

  • abstract로 설정
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
	
    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    private int price;
}

자식 클래스 - Album, Movie, Book 클래스

profile
개발자 싱상형

2개의 댓글

comment-user-thumbnail
2022년 6월 23일

상세한 설명 정말 감사드려요

1개의 답글