JPA - 상속관계매핑

KoK·2025년 6월 27일

JPA

목록 보기
5/8
post-thumbnail

JPA로 도메인 모델을 설계하다보면 공통된 속성을 가진 여러 엔티티들을 만들어야 하는 상황이 생길 수 있다.
예를 들어 Item 이라는 상위개념 아래에 Book, Movie, Album 같은 하위개념이 있을 수 있다.
이럴 때 각 엔티티마다 같은 필드를 반복해서 정의하는 대신,
자바의 "상속" 개념을 활용해 상위 → 하위 개념으로 구조화할 수 있다.

이번 글에서는 JPA에서의 "상속" 을 어떻게 테이블에 매핑하는지, 세가지 상속매핑 전략, 특징에 대해서 정리해보려고 한다.


1. 상속매핑이란?

2. 상속매핑 전략

@Inheritance(strategy=InheritanceType.XXX) 
// JOINED: 조인 전략
// SINGLE_TABLE: 단일 테이블 전략
// TABLE_PER_CLASS: 구현 클래스마다 테이블 전략

2-1. SINGLE_TABLE

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Item {

    @Id @GeneratedValue
    private Long id;

    private String name;
    private int price;
}


출처 : 인프런 - 자바 ORM표준 JPA프로그래밍 - 기본편(김영한)

하나의 테이블에 모든 데이터를 다 넣음

장점단점
• 조인이 필요 없으므로 일반적으로 조회 성능이 빠름
• 조회 쿼리가 단순함
• 자식 엔티티가 매핑한 컬럼은 모두 null 허용
• 단일 테이블에 모든 것을 저장하므로
테이블이 커질 수 있다.
상황에 따라서 조회 성능이 오히려 느려질 수 있다.

2-2. JOINED

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Item {

    @Id @GeneratedValue
    private Long id;

    private String name;
    private int price;
} 

출처 : 인프런 - 자바 ORM표준 JPA프로그래밍 - 기본편(김영한)

장점단점
• 테이블 정규화
• 외래 키 참조 무결성 제약조건 활용가능
• 저장공간 효율화
• 조회시 조인을 많이 사용, 성능 저하
• 조회 쿼리가 복잡함
• 데이터 저장시 INSERT SQL 2번 호출

2-3. TABLE_PER_CLASS

@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;
    private String isbn;
}

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

생성되는 테이블 예시
Book

IDNAMEAUTHORISBN
1해리포터J.K롤링12345

Movie

IDNAMEDIRECTORACTOR
2인셉션크리스토퍼 놀란레오나르도 디카프리오

SELECT * FROM Item 불가능. 계층 전체 조회 시 union 필요.

장점단점
• 테이블 독립적
→ 자식만 단독으로 조회할 때 효율적
• null 컬럼 없음
• 부모 타입으로 전체 조회 불가능 (UNION 필요)
• ID 중복 관리 어려움
• 실무에서 거의 안 씀

3. DTYPE

3-1. DTYPE이란?

DTYPE은 JPA가 상속 매핑 시 자동으로 생성하는 "구분자(Discriminator)" 컬럼이다.
어떤 자식 클래스의 인스턴스인지를 식별하기 위해 사용된다.

  • @Inheritance 전략 중 SINGLE_TABLE 또는 JOINED 전략을 사용할 때 생성됨

  • @DiscriminatorColumn(name = "DTYPE")을 명시하지 않아도 기본값(DTYPE)으로 자동 생성됨 @Inheritance 전략 중 SINGLE_TABLE 또는 JOINED 전략을 사용할 때 생성됨

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
}

@Entity
@DiscriminatorValue("BOOK")
public class Book extends Item {
    private String author;
}

생성된 테이블

IDNAMEAUTHORDTYPE
1해리포터J.K롤링BOOK
2인터스텔라NULLMOVIE

3-2. 사용하는 이유

  • 부모 테이블에서 데이터를 조회할 때 어떤 자식 타입인지 구분하기 위함
  • @DiscriminatorValue 를 지정하지 않으면 기본적으로 클래스 이름이 들어감

4. @MappedSuperclass


출처 : 인프런 - 자바 ORM표준 JPA프로그래밍 - 기본편(김영한)

  • id, name, createdDate 같은 공통 필드가 여러 엔티티에 반복될 때
  • 공통 속성만 객체로 상속받고, 테이블은 독립적으로 존재하게 만들고 싶을 때

사용예시

@Getter
@Setter
@MappedSuperclass
public class BaseEntity {

    private String createdBy;
    private LocalDateTime createdDate;
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;
}
@Entity
@Getter
@Setter
public class Team extends BaseEntity {

    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;

    @OneToMany
    @JoinColumn(name = "TEAM_ID")
    private List<Member> members = new ArrayList<>();
}
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Member extends BaseEntity {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String username;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
    private Team team;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;

    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts = new ArrayList<>();
}

@MappedSuperclass는 공통 필드를 상속만 받고, 엔티티와 테이블은 따로 유지하고 싶을 때 사용하는 구조이다.

마무리

JPA에서 상속 매핑은 단순히 객체지향적인 설계를 넘어서,
어떻게 데이터베이스 테이블을 나눌지에 대한 전략이기도 하다.
각각의 전략은 성능, 쿼리 복잡도, 유지보수성 측면에서 명확한 차이를 가지므로, 상황에 맞게 신중하게 선택하는 것이 중요할것 같다.

“객체지향스럽게 짜면 되겠지?” 하고 상속만 썼다가, 테이블 구조가 엉망이 되거나 쿼리 성능이 급격히 떨어질 수 있다.
도메인 구조, 데이터 양, 성능 요건을 고려하여
전략을 신중히 선택해야 할 것 같다.

profile
개발 이것저것

0개의 댓글