250218 TIL

2025. 2. 18. 17:55·TIL

상속 매핑 전략

객체 지향적인 상속 구조를 관계형 데이터베이스의 테이블로 변환하는 방법

JPA는 3가지 주요 상속 매핑 전략을 제공

1. 단일 테이블 전략 (Single Table Strategy)

모든 자식 클래스를 하나의 테이블에 저장하는 방식

  • 한 개의 테이블에 모든 자식 클래스의 데이터를 저장
  • 부모 클래스와 자식 클래스의 모든 속성을 포함하는 하나의 테이블만 생성됨
  • 자식 클래스를 구분하기 위해 **"구분 컬럼(DTYPE)"**을 추가함
  • 테이블이 하나라서 조회 성능이 빠르고, 조인이 필요 없음
  • 불필요한 NULL 값이 많이 저장될 수 있음
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 단일 테이블 전략
@DiscriminatorColumn(name = "dtype") // 구분 컬럼 설정
public class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
}

@Entity
@DiscriminatorValue("B") // 구분 컬럼에 들어갈 값
public class Book extends Item {
    private String author;
}

@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
    private String director;
}

 

✅ 생성된 테이블 구조

id  dtype  name  author  director
1 B Java 홍길동 NULL
2 M Inception NULL 크리스토퍼 놀란

2. 조인 전략 (Joined Strategy) (정규화)(기본값)

부모 클래스와 자식 클래스를 각각 테이블로 만들고, 관계를 맺는 방식

  • 부모 클래스와 자식 클래스가 각각 별도의 테이블로 저장됨
  • 자식 테이블이 부모 테이블을 PK + FK(외래 키)로 참조함
  • 테이블 정규화가 잘 되어 중복 데이터가 줄어들고, NULL이 적어짐
  • 조회할 때 조인이 필요하므로 성능이 다소 느릴 수 있음
@Entity
@Inheritance(strategy = InheritanceType.JOINED) // 조인 전략
@DiscriminatorColumn(name = "dtype") // 구분 컬럼 설정 (선택 사항)
public class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
}

@Entity
public class Book extends Item {
    private String author;
}

@Entity
public class Movie extends Item {
    private String director;
}

 

✅ 생성된 테이블 구조

부모 테이블 (Item)

id  name
1 Java
2 Inception

 

자식 테이블 (Book)

id  author
1 홍길동

 

자식 테이블 (Movie)

id  director
2 크리스토퍼 놀란

3. 테이블 별퍼 클래스 전략 (Table Per Class Strategy)

각 자식 클래스를 독립적인 테이블로 저장하고, 부모 테이블은 만들지 않는 방식

  • 부모 클래스를 위한 테이블이 없고, 각 자식 클래스가 독립적인 테이블을 가짐
  • 데이터 조회 시 UNION을 사용해야 할 수도 있어서 성능이 떨어질 수 있음
  • 테이블 정규화가 덜 되어 데이터가 중복될 가능성이 있음
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) // 테이블 별퍼 클래스 전략
public class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
}

@Entity
public class Book extends Item {
    private String author;
}

@Entity
public class Movie extends Item {
    private String director;
}

 

✳️ @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) 전략을 사용할 때       GenerationType.IDENTITY를 사용할 수 없다

▶️부모 테이블 없이 자식 클래스 마다 별도의 테이블을 생성하기 때문에 각 테이블이 따로 AUTO_INCREMENT를 가지게 되고, 서로 독립적으로 ID를 생성

▶️같은 ID 값이 여러 테이블에서 중복될 수 있음

 

❔왜 중복 되면 안되나❔

JPA에서는 엔티티의 기본 키(PK)는 애플리케이션 전체에서 유일해야 한다는 원칙이 있다

1️⃣JPA의 find() 메서드는 ID 기반으로 엔티티를 조회

EntityManager em = ...;
Vehicle vehicle = em.find(Vehicle.class, 1L);  // id = 1인 객체 조회

find()를 호출할 때, Vehicle 테이블이 없으니 모든 자식 테이블을 조회해야 하는데, 여러 개의 결과가 나올 가능성이 있음

 

2️⃣영속성 컨텍스트의 1차 캐시 문제

JPA는 1차 캐시(영속성 컨텍스트)를 사용해 이미 조회한 엔티티를 캐싱

id=1을 가진 Car 객체를 조회했는데, 나중에 id=1을 가진 Truck 객체를 찾으면 캐시에서 Car 객체를 반환할 가능성이 있음.

→ 즉, Car와 Truck이 같은 ID를 가지면 캐싱과 조회 로직이 꼬일 수 있음

 

3️⃣상속 구조에서 @MappedSuperclass와 다름 @MappedSuperclass 사용 시 에는 필드만 공유 하고 부모 클래스가 없음

TABLE_PER_CLASS 전략에서는 JPA가 부모 타입(Vehicle)으로도 조회해야 하기 때문에, 모든 테이블을 UNION으로 조회하는데, ID가 중복되면 예상치 못한 결과가 나올 수 있음.

 

▶️ 그래서 ! @GeneratedValue(strategy = GenerationType.TABLE) 사용 : 키 생성 전용 테이블

모든 테이블이 동일한 ID 시퀀스를 공유하도록 설정하여 ID가 중복되지 않음

 

✅ 생성된 테이블 구조

Book 테이블

id  name  author
1 Java 홍길동

 

Movie 테이블

id  name  director
2 Inception 크리스토퍼 놀란

@MappedSuperclass

  • 엔티티가 아니지만, 공통 필드를 가진 슈퍼클래스로 사용할 때 적용하는 어노테이션
  • 이 클래스를 상속받는 서브클래스(@Entity가 적용된 클래스)만 테이블이 생성
  • @MappedSuperclass 자체는 테이블을 생성하지 않음
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@MappedSuperclass // 테이블이 생성되지 않는 부모 클래스
@Getter
@Setter
public abstract class Vehicle3 {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // IDENTITY 사용 가능
    private Long id;
    private String manufacturer;
}

@Entity
@Getter
@Setter
class Car3 extends Vehicle3 { // Vehicle3을 상속
    private int seatCount;
}

@Entity
@Getter
@Setter
class Truck3 extends Vehicle3 { // Vehicle3을 상속
    private double payloadCapacity;
}
CREATE TABLE Car3 (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    manufacturer VARCHAR(255),
    seatCount INT
);

CREATE TABLE Truck3 (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    manufacturer VARCHAR(255),
    payloadCapacity DOUBLE
);

 

  @MappedSuperclass @Inheritance
테이블 생성 여부 부모 클래스 테이블 ❌ (X) 부모 클래스 테이블 ⭕ (O)
필드 상속 여부 단순히 필드만 상속 필드 & 테이블 계층 구조 유지
사용할 때 공통 필드만 상속받고 싶을 때 계층형 엔티티(상속 구조)로 관리할 때

 

📌비교 정리

전략  장점 단점
단일 테이블 (Single Table) 조회 성능이 좋음, 쿼리가 단순함 NULL이 많아질 수 있음
조인 전략 (Joined) 정규화로 중복 데이터가 줄어듦 조회 시 조인이 필요해 성능 저하 가능
테이블 별퍼 클래스 (Table Per Class) 서브타입별로 독립적인 테이블을 가짐 UNION 연산이 필요해 성능 저하 가능

 

📌어떤 전략을 선택해야 하나?

  • 조회 성능이 중요하고, 자식 클래스 간 속성 차이가 크지 않다

→ 단일 테이블 전략 (Single Table) 추천

  • 데이터 정규화가 중요하고, NULL 값을 피하고 싶다

→ 조인 전략 (Joined) 추천

  • 각 자식 클래스가 완전히 독립적인 테이블이 필요하다

→ 테이블 별퍼 클래스 전략 (Table Per Class) 선택 가능

'TIL' 카테고리의 다른 글

250220 TIL  (0) 2025.02.20
250219 TIL  (0) 2025.02.19
250214 TIL  (0) 2025.02.16
250212 TIL  (1) 2025.02.13
250206 TIL  (0) 2025.02.07
'TIL' 카테고리의 다른 글
  • 250220 TIL
  • 250219 TIL
  • 250214 TIL
  • 250212 TIL
Jiyuuuuun
Jiyuuuuun
  • Jiyuuuuun
    Hello, World!
    Jiyuuuuun
  • 전체
    오늘
    어제
    • 분류 전체보기 (107)
      • TIL (56)
      • CS (12)
        • Network (4)
        • Algorithm (6)
      • JAVA (5)
      • Project (10)
        • HakPle (3)
        • JUSEYO (4)
      • Spring (2)
      • C (3)
      • C++ (16)
      • Snags (2)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    back-end
    멋쟁이사자처럼
    db
    my_favorite_place
    Docker
    JPA
    SQL
    부트캠프
    springboot
    java
    nginx
    hakple
    javascript
    node.js
    JDBC
    front-end
    juseyo
    react
    CSS
    Kubernetes
    HTML
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Jiyuuuuun
250218 TIL
상단으로

티스토리툴바