web/JPA

JPA 상속관계 매핑 전략

반응형

객체 지향으로 데이터베이스 중심 매핑을 변경하기 위해서 가장 애매한게 상속이다. 이런 상속관계속에서 테이블로 구현할 3가지 방법을 선택할 있다.


1) 각각의 테이블로 변환 : 각각을 모두 테이블로 만들고 조회할 조인을 사용.

2) 통합 테이블로 변환 : 테이블을 하나만 사용해서 통합 

3) 서브타입 테이블로 변환 : 서브 타입마다 하나의 테이블을 만드는 방식.



순서대로 하나씩 정리해보자.




각각의 테이블로 변환 (조인전략)

- 부모와 각각의 자식 엔티티를 모두 각자의 테이블로 만들고 부모의 기본키와 자식의 외래키를 사용하여 조인하여 사용한다.

-  자식 엔티티의 타입을 구별하기 위한 DTYPE 컬럼을 구분컬럼으로 추가하여 사용한다. (없어도 무관)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Culture {
  
  @Id @GeneratedValue
  @Column(name = "CULTURE_ID")
  private Long id;
  
  private String name;
  private int price;
  
}
 
cs

-> 부모 추상 클래스 Culture 선언된 애노테이션에 대한 설명은 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
@Inheritance(strategy = InheritanceType.JOINED) : 조인전략 사용을 의미
@DiscriminatorColumn(name = "DTYPE") : 부모 클래스에 구분 컬럼으로 써 자식 테이블을 구분할 때 사용할 키로 사용된다. 기본값은 DTYPE이며 바꿔서 사용가능 (해당 기능을 사용하지 않아도 무관하다.)
 
 
@Entity
@DiscriminatorValue("M")
public class Movie {
 
  private String artiest;
  private String genre;
 
}
cs


기본적으로 사용하는 자식클래스 형식이다. 기본적으로 부모 테이블의 ID 컬럼명을 승계받아 사용 하지만 만약 변경하고 싶은 경우 클래스 위에 @PrimaryKeyJoinColumn(name = "MOVIE_ID")처럼 정의해서 사용할 있다.


조인전략의 장점은 저장공간을 효율적으로 관리하거나 테이블의 정규성이 지켜진다는 점이 있지만 조회할 조인이 많아지고 조회 쿼리시 귀찮아지며 수정이 발생하면 부모와 자식 테이블 두번을 해주어야한다.

 


 통합 테이블로 변환 (단일 테이블 전략)

부모의 속성과 자식의 속성을 하나의 테이블로 사용하는 것이다. 그리고 구분 컬럼 DTYPE 추가하여 해당 테이블이 어떤 자식 엔티티를 기반으로 만들어진 테이블인지 구분한다. (DTYPE 어떤자식인지 구분하기 위해 사용한다. 만약 속성이 같은 자식인 경우 구분이 안되기 때문이다.) 해당 전략의 단점으로는 자식 엔티티에 추가된 필드는 필수가 아니기 때문에 null 입력 되어도 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Culture {
 
  @Id @GeneratedValue
  @Column(name = "CULTURE_ID")
  private Long id;
 
  private String name;
  private int price;
 
}
 
cs

-> Inheritance(strategy = InheritanceType.SINGLE_TABLE) 조인 타입을 단일 테이블 전략으로 지정한다. 


1
2
3
4
5
6
7
@Entity
@DiscriminatorValue("M")
public class Movie extends Culture {
 
  private String genre;
 
}
cs


 하나의 테이블로 지정되기 때문에 조인전략과 다르게 자식클래스를 구분할 있는 DTYPE 무조건 추가되어야 한다. 방식은 하나로 묶여있어 쿼리가 단순하다는 장점이 있지만 자식 엔티티의 필드의 null 무조건 허용해줘야 한다는 것과 자식마다 성격이 모두 달라도 테이블에 필요없는 필드까지 추가되어 있어야 하는 문제점이 있다.



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

 자식 엔티티 마다 별도의 모든 테이블을 만들어 주는 방식이다. 부모와 자식을 키로 묶어서 사용하는 조인 방식과 다르게 자식 마다 부모의 속성과 자식의 속성을 모두 포함한 엔티티를 개별적으로 모두 만드는 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Culture {
 
  @Id @GeneratedValue
  @Column(name = "CULTURE_ID")
  private Long id;
 
  private String name;
  private int price;
 
}
cs


- 단일테이블 전략과 다르게 모든 자식 테이블이 별도로 만들어지기 때문에 필요없는 필드가 추가되지 않아서 not null조건을 넣어줄 있다. 하지만 모두 만들어야하고 자식테이블끼리 합칠 성능의 문제가 발생할 있다. 가장 비효율적인 방법으로 일반적으로 조인이나 단일 테이블 전략중에서 사용한다.


- 참고 JAVA ORM 표준 JPA 프로그래밍


반응형