JAVA

[JAVA] JPA 고급 매핑 (상속 관계 매핑)

응디 2021. 12. 16. 11:10

상속관계 매핑

관계형 데이터 베이스는 상속 관계를 구현 할 수 없다는 단점을 가지고 있다.

그나마 슈퍼타입, 서브타입 관계가 객체 상속과 유사하다.

 

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

  1. 각각 테이블로 변환 : 조인 전략(Joined)
  2. 통합 테이블로 변환 : 단일 테이블 전략
  3. 서브타입 테이블로 변환 : 구현 클래스마다 테이블 전략

 

매핑 시 주로 사용하는 어노테이션

1. @Inheritance(strategy=InheritanceType.XXXX)

  • JOINED : 조인 전략
  • SINGLE_TABLE : 단일 테이블 전략
  • TABLE_PER_CLASS : 구현 클래스마다 테이블 전략

2. @DiscriminatorColumn(name="DTYPE") → default가 DTYPE

3. @DiscriminatorValue("XXX")


단일 테이블 전략(기본값)

  • 단일 테이블은 Inheritance의 기본값이기 때문에 명시하지 않아도 사용 가능하다.
  • 단일 테이블은 DTYPE이 자동으로 무조건 들어간다. (DiscriminatorColumn이 없어도) : 그게 없으면 단일테이블은 구분하기 너무 힘들기 때문에 자동으로 들어간다.

장점

: 조인이 필요없어 일반적으로 조회성능이 빠름, 조회쿼리가 단순하다.

 

단점

: 자식 엔티티가 매핑한 컬럼은 모두 null 허용(무결성 문제),

: 단일 테이블에 모든 것을 저장하므로 테이블이 커질수 있다.

: 상황에 따라 조회 성능이 오히려 느릴 수 있다.

 

아래는 사용 예시 이다.

/* Item.java */
@Entity
// 기본이 싱글 테이블(굳이 안적어도됨)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Item {

    @Id @GeneratedValue
    private Long id;

    private String name;

    private int price;

}


/* Movie.java */
@Entity
public class Movie extends Item{
    private String director;
    private String actor;

}

// ... 외 Book, Album 존재 추후 작성

위에 처럼 작성 후 실행 시키면 아래 이미지 처럼 하나의 테이블에 모든 컬럼이 생성된다.

단일테이블 쿼리 생성 예시
단일테이블 DB 예시

 


조인전략(JOINED)

  • 조인전략은 조회 할 때도 조인해서 가져옴

장점

: 테이블 정규화, 외래키 참조 무결성 제약조건 활용가능, 저장공간 효율성

 

단점

: 조회 시 조인을 많이 사용, 성능저하( 잘 조인하면 괜찮긴함 )

: 조회 쿼리가 복잡하다.

: 데이터 저장 시 insert 2번 호출( 부모와 자식 둘다 데이터를 넣어줘야하기 때문 )

 

/* Item.java */
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Item {

    @Id @GeneratedValue
    private Long id;

    private String name;

    private int price;

}


/* Movie.java */
@Entity
public class Movie extends Item{
    private String director;
    private String actor;

}

// ... 외 Book, Album 존재 추후 작성
Movie movie = new Movie();
movie.setDirector("봉준호");
movie.setActor("송강호");
movie.setName("기생충");
movie.setPrice(12000);

em.persist(movie);

조인 전략 사용 후 Movie 값을 등록 하면 아래 이미지 처럼 결과가 등록됨

만약 조인 전략 사용 시 *DTYPE을 지정하고 싶다면?? DiscriminatorColumn 사용!

* 여기서 DTYPE 이란 어떤 테이블을 조회한건지 구분해주는 구분 컬럼을 말한다!

 

DiscriminatorColumn은 컬럼 이름이 기본값으로 'DTYPE' 이 들어가고 이름을 지정하고 싶을때는

DiscriminatorColumn( name = "test" ) 이런 식으로 사용한다.

DTYPE이 없으면 어떤 타입으로 데이터가 삽입된건지 알기 어렵기 때문에 웬만하면 사용하는걸 권장!

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 기본이 싱글 테이블
@DiscriminatorColumn                            // 기본 컬럼명이 DTYPE
public abstract class Item {
...
}

DiscriminatorColumn 사용 예시

만약 DTYPE 의 value 값을 클래스 이름이 아닌 내가 지정해 주고 싶다면?? DiscriminatorValue 사용!

@Entity
@DiscriminatorValue("M")     // DTYPE의 value 값을 다른걸로 사용하고싶을때
public class Movie extends Item{
...
}

DiscriminatorValue 사용 예시

 


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

  • 단순하게 값을 넣었다 뺄때는 편하다.
  • 구현 클래스의 문제점 → 쓰면 안되는 전략 : 데이터를 삽입할때는 좋다. 하지만 조회할때 부모 클래스인 Item으로 Movie 데이터를 조회하려면 union으로 모든 테이블을 합치기 때문에 성능이 떨어진다.( 비효율적 )
  • 이 전략은 데이터베이스 설계자와 ORM 전문가 둘다 비 추천

장점

: 서브 타입을 명확하게 구분해서 처리 할 때 효과적, not null 조건 사용가능

 

단점

: 여러 자식 테이블을 함께 조회 할 때 성능이 느림(union sql), 자식 테이블을 통합해서 쿼리하기 어려움

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 
@DiscriminatorColumn                            
public abstract class Item {
...
}

조회 시 문제점 예시(union)

'JAVA' 카테고리의 다른 글

[JAVA] 프록시  (0) 2022.01.04
[JAVA] @MappedSuperclass  (0) 2022.01.04
[JAVA] JPA 다양한 연관관계 매핑  (0) 2021.12.09
[JAVA] JPA 연관관계 매핑( 양방향 )  (0) 2021.11.17
[JAVA] JPA 연관관계 매핑( 단방향 )  (0) 2021.11.16