@Inheritance

XingXi·2024년 1월 3일
0

JPA

목록 보기
13/23
post-thumbnail

🍕 Reference

자바 ORM 표준 JPA 프로그래밍 : 교보문고
자바 ORM 표준 JPA 프로그래밍 - 기본편 : 인프런

객체에는 상속이라는 개념이 존재한다. 하지만 RDB 에서 상속이라는 개념은 존재하지 않는다.
때문에 객체와 테이블간 패러다임문제가 발생한다. 하지만 RDB에서는 객체 상속과 비슷한 모델인 Super, Sub 타입이 존재한다. 이 논리 모델을 물리적 모델로 구현하기 위한 방법을 JPA 에서 지원해 주고 있다.

1. @Inheritance(strategy = InheritanceType.JOINED)

JPA 에서 지원해주는 상속 전략 중 하나로 상위 테이블과 하위 테이블을 생성한다.

Hibernate: 
    
    create table Album (
       artist varchar(255),
        id bigint not null,
        primary key (id)
    )
Hibernate: 
    
    create table Book (
       author varchar(255),
        isbn varchar(255),
        id bigint not null,
        primary key (id)
    )
Hibernate: 
    
    create table Item (
       DTYPE varchar(31) not null,
        id bigint not null,
        name varchar(255),
        price integer not null,
        primary key (id)
    )
Hibernate: 
    
    create table Movie (
       actor varchar(255),
        director varchar(255),
        id bigint not null,
        primary key (id)
    )

상위 클래스에 @Inheritance(strategy = InheritanceType.JOINED) 선언하여 사용

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public class Item
{
    @Id @GeneratedValue
    private Long id;

구조

  • Super, Sub 테이블간 기본키를 공유하는 형테로 데이터를 저장한다.
  • 때문에 외래키 제약조건이 줄어 무결성 제약 조건에 대한 부하가 적어진다.
  • Sub 클래스가 별도의 테이블에 저장된다.

장점

  1. 테이블 정규화
  2. 기본키를 공유하는 형테로 데이터를 저장하기 때문에
    외래키 제약조건이 줄어 무결성 제약 조건에 대한 부하 적음
  3. Sub Class 별로 테이블에 저장되므로 Sub class 에 해당하는 필드만 포함하고 이로 인해
    SCHEME가 간결해진다.

단점

1. Sub 객체 Insert 시 Insert 쿼리가 2개 발생한다.
상위 클래스 Item 이 먼저 Insert 와 하위 클래스 Movie 가 같이 Insert 되고 있다.
2. 하위 객체 조회 시 JOIN Query 발생

Movie findMovie = em.find(Movie.class, movie.getId());
            System.out.println("find Movie : "+findMovie.getActor());
Hibernate: 
    select
        movie0_.id as id1_2_0_,
        movie0_1_.name as name2_2_0_,
        movie0_1_.price as price3_2_0_,
        movie0_.actor as actor1_3_0_,
        movie0_.director as director2_3_0_ 
    from
        Movie movie0_ 
    inner join
        Item movie0_1_ 
            on movie0_.id=movie0_1_.id 
    where
        movie0_.id=?
find Movie : one

테이블 구조가 복잡해지면 복잡한 JOIN Query 가 생성된다. 이로인한 성능저하 또한 발생할 수 있다.

@DiscriminatorColumn

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public class Item
{
    @Id @GeneratedValue
    private Long id;

    private String name;

    private int price;

상위 객체에서 @Inheritance 와 함께 선언되는 Annotation 이며
상위 객체 테이블에서 구분을 위한 컬럼이 생성된다.
기본값이 DTYPE인 컬럼이 상위 객체 테이블에 생성되고
해당 컬럼의 값은 설정하지 않으면 Entity명이 들어간다.
하위 객체에 @DiscriminatorValue 를 사용하면 사용자가 값을 직접 정의할 수 있다.

  • @DiscriminatorValue(사용자정의 이름)
    ex)
@Entity
@DiscriminatorValue("M")
public class Movie extends Item


2. @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Item
{

상위 객체의 클래스에 모든 하위 객체의 필드들을 넣는 전략

Hibernate: 
    
    create table Item (
       DTYPE varchar(31) not null,
        id bigint not null,
        name varchar(255),
        price integer not null,
        author varchar(255),
        isbn varchar(255),
        actor varchar(255),
        director varchar(255),
        artist varchar(255),
        primary key (id)
    )

특이점

@DiscriminatorColumn 을 추가적으로 선언하지 않아도
DTYPE 이 자동으로 생성된다.

장점

  1. 구조가 간단하다
  2. 상위 객체와 하위 객체간 JOIN 이 필요 없어서 조회 성능이 빠르다
  3. Insert 도 1번만 발생하고 쿼리가 단순하다.

단점

  1. 같은 상위 객체의 다른 하위 객체들의 필드들을 NULL 허용
  2. 하위 객체가 많아 질 경우 성능저하 문제 발생

--

3. @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

상위 객체의 테이블을 생성하지 않고 하위 객체에 대한 테이블만 생성

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item
{
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: 
    
    create table Album (
       id bigint not null,
        name varchar(255),
        price integer not null,
        artist varchar(255),
        primary key (id)
    )
Hibernate: 
    
    create table Book (
       id bigint not null,
        name varchar(255),
        price integer not null,
        author varchar(255),
        isbn varchar(255),
        primary key (id)
    )
Hibernate: 
    
    create table Movie (
       id bigint not null,
        name varchar(255),
        price integer not null,
        actor varchar(255),
        director varchar(255),
        primary key (id)
    )

장점

  1. 하위 타입 명확하게 구분해서 처리 할 수 있다.

단점

  1. 상위 타입 객체에서 하위 타입 조회하기에 어려움 ( 여러 자식 테이블 조회 시 UNION JOIN 발생 )
Item findMovie = em.find(Item.class, movie.getId());
System.out.println("find Movie : "+findMovie.getName());
Hibernate: 
    select
        item0_.id as id1_2_0_,
        item0_.name as name2_2_0_,
        item0_.price as price3_2_0_,
        item0_.author as author1_1_0_,
        item0_.isbn as isbn2_1_0_,
        item0_.actor as actor1_3_0_,
        item0_.director as director2_3_0_,
        item0_.artist as artist1_0_0_,
        item0_.clazz_ as clazz_0_ 
    from
        ( select
            id,
            name,
            price,
            author,
            isbn,
            null as actor,
            null as director,
            null as artist,
            1 as clazz_ 
        from
            Book 
        union
        all select
            id,
            name,
            price,
            null as author,
            null as isbn,
            actor,
            director,
            null as artist,
            2 as clazz_ 
        from
            Movie 
        union
        all select
            id,
            name,
            price,
            null as author,
            null as isbn,
            null as actor,
            null as director,
            artist,
            3 as clazz_ 
        from
            Album 
    ) item0_ 
where
    item0_.id=?
find Movie : one

요약하면

@Inheritance를 통해 객체의 상속을 테이블에서 구현할 수 있고
전략에 따라 구조변경이 쉽다!

0개의 댓글