[JPA] 상속관계 매핑

atdawn·2024년 6월 1일

SPRING BOOT+JPA

목록 보기
18/49

자바와 같은 객체지향에서는 클래스끼리 상속관계가 존재하지만, 관계형 데이터베이스는 상속관계를 지원하지 않는다.
=> 관계형 데이터베이스는 슈퍼타입 서브타입 논리모델 관계 모델링 기법을 통해 객체의 상속관계를 매핑할 수 있음.

슈퍼타입 서브타입 논리모델 -> 물리모델 구현 3가지 방법

3가지 전략을 통해 매핑하기 위해서는 부모 클래스에
@Inheritance(strategy=InheritanceType.XXX)의 stategy를 설정한다.

  1. JOINED : 각각의 테이블로 변환 (조인 전략)
  2. SINGLE_TABLE : 통합 테이블로 변환 (단일 테이블 전략) ! 기본값
  3. TABLE_PER_CLASS : 서브타입 테이블로 변환 (구현 클래스마다 테이블 전략)

주요 어노테이션

  1. @Inheritance(strategy=InheritanceType.XXX) : 3가지 전략 중 하나를 선택하는 어노테이션
  2. @DiscriminatorColumn(name="DTYPE")
    • 부모 클래스에 선언
    • 하위 클래스를 구분하는 용도의 컬럼
    • 기본값 : DTYPE
    • 하이버네이트의 조인 전략에서는 @DiscriminatorColumn을 선언하지 않으면 DTYPE 컬럼이 생성되지 X => 넣어주는 것이 명확
  3. @DiscrminatorValue("XXX")
    • 하위 클래스에 선언
    • 엔티티를 저장할때 슈퍼타입의 구분 컬럼에 저장할 값을 지정
    • 기본값 : 클래스 이름 (어노테이션을 선언하지 않을 경우)

1. 조인 전략 예시

import javax.persistence.*;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Vehicle {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // getters and setters
}

@Entity
@DiscriminatorValue("CAR")
public class Car extends Vehicle {
    private int seatingCapacity;
    // getters and setters
}

@Entity
@DiscriminatorValue("TRUCK")
public class Truck extends Vehicle {
    private double payloadCapacity;
    // getters and setters
}
  • 부모 클래스에 @Inheritance(strategy = InheritanceType.JOINED) 를 선언하여 상속 전략을 조인 전략으로 설정
  • 부모 클래스에 @DiscriminatorColumn(name = "DTYPE")을 선언하여 하위 클래스의 값을 구분하는 컬럼 생성 (생략가능)
  • 하위 클래스에 각각 @DiscriminatorValue("XXX") 을 선언하여 부모테이블에서 "CAR" 인지 "TRUCK" 인지 구분할 수 있도록 함


2. 단일 테이블 전략 예시

import javax.persistence.*;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Vehicle {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // getters and setters
}

@Entity
@DiscriminatorValue("CAR")
public class Car extends Vehicle {
    private int seatingCapacity;
    // getters and setters
}

@Entity
@DiscriminatorValue("TRUCK")
public class Truck extends Vehicle {
    private double payloadCapacity;
    // getters and setters
}
  • 부모테이블에 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)을 선언하여 상속 전략을 단일 테이블 전략으로 설정
  • 부모테이블에 @DiscriminatorColumn(name = "DTYPE")을 선언하여 하위 클래스를 구분하는 컬럼을 설정
  • 하위 클래스에 각각 @DiscriminatorValue("XXX") 을 선언하여 부모테이블에서 "CAR" 인지 "TRUCK" 인지 구분할 수 있도록 함


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

import javax.persistence.*;

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // getters and setters
}

@Entity
public class Car extends Vehicle {
    private int seatingCapacity;
    // getters and setters
}

@Entity
public class Truck extends Vehicle {
    private double payloadCapacity;
    // getters and setters
}
  • 부모테이블에 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS): 상속 전략을 구체 클래스당 하나의 테이블로 설정
  • 구체 클래스에는 @DiscriminatorColumn@DiscriminatorValue 어노테이션을 사용할 필요가 X


전략 선택 고려사항

  • 단일 테이블 전략: 조회 성능이 우수하고 쿼리가 단순하지만, 많은 NULL 값과 큰 테이블 크기를 감수해야 함.
  • 조인 전략: 데이터 정규화와 저장 공간 효율성이 뛰어나지만, 조회 쿼리가 복잡하고 조인 비용이 발생 함.
  • 구체 클래스 전략: 테이블 구조가 단순하고 스키마 변경이 독립적이지만, 데이터 중복과 저장 공간 비효율성을 고려해야 함.

3가지 전략들의 장단점을 고려하여 애플리케이션의 요구사항에 맞는 전략을 선택하는 것이 중요하다.

profile
복습 복습 복습

0개의 댓글