본문 바로가기
JPA

JPA - 상속관계 매핑

by 왈레 2022. 4. 10.

상속관계 매핑

• 관계형 데이터베이스는 상속 관계가 존재하지 않는다.

• 데이터베이스의 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사하다.

• 상속관계 매핑이란 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑하는 것이다.

 

※ DB 설계에는 논리모델(왼쪽)이 있고 물리모델(오른쪽)이 있다.

 

 

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

1. 각각 테이블로 변환 -> 조인 전략 (권장)

2. 통합 테이블로 변환 -> 단일 테이블 전략 (기본설정)

3. 서브타입 테이블로 변환 -> 구현 클래스마다 테이블 전략 (추천하지않음)

 

참고로 상위 클래스는 반드시 abstract class로 만들어야한다.

밑에 코드예제에서는 class를 abstract로 선언하지 않았다.

 

class를 abstract을 선언하지 않은상태로 "구현 클래스마다 테이블 전략"으로 설정하면 상위 테이블이 생성된다.

(원래는 생성되면 안되는데 abstract class로 만들지 않으면 테이블이 단독적으로 사용될 수 있다는 의미로 해석되서 JPA가 테이블을 그냥 생성해버린다.)

 

 

주요 어노테이션

@Inheritance(strategy=InheritanceType.XXX)

  1. JOINED : 조인 전략 (권장)
  2. SINGLE_TABLE : 단일 테이블 전략 (기본설정)
  3. TABLE_PER_CLASS : 구현 클래스마다 테이블 전략 (추천하지 않음)
@Entity
@Inheritance(strategy = InheritanceType.XXX)
public class Item {
    ...// 상위클래스
}

 

 

@DiscriminatorColumn(name = "DTYPE")

  • 상위 클래스에 써준다.
  • 구분을 위한 "DTYPE" 컬럼을 상위 테이블에 자동으로 만들어준다. (name 속성이 없으면 "DTYPE" 기본설정)
  • DTYPE 컬럼에는 하위 테이블의 클래스명이 들어간다. (Movie, Album, Book)
  • name 속성명을 명시하지 않으면 컬럼명은 자동으로 "DTYPE"
  • 이 속성을 명시하지않으면 조인전략에서는 컬럼을 만들지 않지만, 단일 테이블 전략에서 자동으로 생성한다.
@Entity
@Inheritance(strategy = InheritanceType.XXX)
@DiscriminatorColumn(name = "DTYPE")
public class Item {
    ...// 상위클래스
}

 

 

@DiscriminatorValue("XXX")

  • 하위 클래스에 써준다.
  • 상위 테이블 DTYPE 컬럼에 들어갈 하위 클래스명을 다른 이름으로 바꾸어줄 수 있다.
  • 이 어노테이션을 선언하지 않을 경우 기본값으로 클래스 이름이 들어간다.
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
    ...// 하위클래스
}

 

 

1. 조인전략

  • 각각을 모두 테이블로 만들고 조회할 때 Join을 사용하는 방법
  • 하위 테이블은 상위 테이블의 PK를 자신의 PK,FK를 동시에 가져간다.
  • 조회시 JPA가 알아서 JOIN해준다. (상위테이블 < -- > 하위테이블)
  • @DiscriminatorColumn 속성을 명시하지 않으면 "DTYPE" 컬럼이 생기지 않는다. (가급적 넣어주자.)
  • 비즈니스적으로 중요하고 복잡한 경우에 사용

 

장점

• 테이블 정규화가 되어있다. (중복이 제거된)

• 외래 키 참조 무결성 제약조건 활용가능

• 저장공간 효율화

• 유지보수에 좋다.

 

단점

• 조회시 조인을 많이 사용, 성능 저하 (큰 문제는 없다.)

• 조회 쿼리가 복잡함

• 데이터 저장시 INSERT SQL 2번 호출 (상위테이블, 하위테이블)

 

 

2. 단일 테이블 전략

  • 단위 테이블 전략은 논리테이블을 그냥 한 테이블로 합치는 전략이다.
  • @DiscriminatorColumn 속성을 명시하지 않아도 자동으로 "DTYPE" 컬럼이 생긴다.
  • 테이블 단순한 구조이거나 확장 가능성이 적을 경우 사용한다.

 

장점

• 조인이 필요 없으므로 일반적으로 조회 성능이 빠름

• 조회 쿼리가 단순함

• insert 쿼리도 한번만 나간다.

 

단점

자식 엔티티가 매핑한 컬럼은 모두 null 허용 (데이터 무결성 관점에서 좋지않다)

• 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다. 상황에 따라서 조회 성능이 오히려 느려질 수 있다.

  (느려지려면 어느정도 임계점이 넘어서야하는데, 넘어서는 경우는 많지않다.)

 

※데이터 무결성이란?

데이터 무결성은 컴퓨팅 분야에서 완전한 수명 주기를 거치며 데이터의 정확성과 일관성을 유지하고 보증하는 것을 가리키며 데이터베이스나 RDBMS 시스템의 중요한 기능이다. 

 

 

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

 

  • 상위 테이블을 없애버리고, 컬럼을 하위 클래스로 다 내린다.
  • 중복이 많다. (정규화되지 않았다.)
  • @DiscriminatorColumn은 넣지않아도 된다. (넣어도 컬럼 생기지도않고 아무런 변화도 없다.)

 

장점

• 서브 타입을 명확하게 구분해서 처리할 때 효과적 (insert나 select할때 효과적) 

• not null 제약조건 사용 가능

 

단점

• 여러 자식 테이블을 함께 조회할 때 성능이 느림(UNION SQL 필요)

• 자식 테이블을 통합해서 쿼리하기 어려움

 

※출처 - 인프런 김영한 JPA

댓글