상속관계 매핑은 무엇일까?
관계형 DB의 상속 관계
--
자바 객체의 상속관계처럼
관계형 DB에는 상속 관계가 존재하지 않는다.
다만 "슈퍼타입", "서브타입" 관계라는 모델링 기법을 통해 객체 상속과 유사한 형태를 만들 수 있다.
즉, 상속관계 매핑은
객체의 상속 구조와 DB의 슈퍼타입, 서브타입 관계를 매핑하는 것을 의미한다.
상속관계 매핑에는 3가지 구현 방법이 존재한다.
- 조인 전략 (각 테이블로 변환)
- 단일 테이블 전략 (통합 테이블로 변환)
- 구현 클래스마다 테이블 전략 (서브타입 테이블로 변환)
조인 전략 (각 테이블로 변환)

Item 테이블을 우선 생성하고
해당 테이블 하위에 알맞은 테이블(Water, Book, Car)을 추가로 생성하며
추가로 필요할 때마다 특정 테이블을 조인하는 방식이다.
예시
Book 데이터에 접근해야 한다면
name, price는 Item 테이블에 존재하고, author, page는 Book 테이블에 존재하므로
두 테이블을 Insert 하여 가져온 다음 조인을 통해 가져온다.
여기서 어떠한 테이블과 조인할지 구분을 해야 하는데
Item 테이블에 "DTYPE"이라는 컬럼을 추가하여 "DTYPE"의 값에 조인할 테이블명 값을 정의하여
"DTYPE"이 Book이면 Book 테이블과 조인하는 식으로 사용한다.
장점
- 테이블 정규화
- 외래 키 참조 무결성 제약조건 활용 가능
- 저장공간 효율화
단점
- 조회 시 조인을 많이 사용하여 성능 저하
- 조회 쿼리가 복잡
- 데이터 저장 시 INSERT SQL문을 2번 호출
단일 테이블 전략 (통합 테이블로 변환)

그냥 하나의 테이블로 모두 합치는 방법으로
여기서도 "DTYPE" 컬럼을 이용하여 현재 어떤 테이블인지 정해서 사용한다.
(DTYPE이 Book이면 해당 테이블은 Book으로 사용)
장점
- 조인이 필요 없어 일반적으로 조회 성능이 빠름
- 조회 쿼리가 단순
단점
- 자식 엔티티가 매핑한 컬럼은 모두 null 허용
- 단일 테이블에 모든 것을 저장하므로 테이블이 커짐 (상황에 따라 조회 성능 저하)
구현 클래스마다 테이블 전략 (서브타입 테이블로 변환)

공통으로 사용하는 데이터를 각 테이블에 모두 넣어주는 방법으로
Item 테이블을 만들지 않고 각 테이블에 모두 할당한다.
해당 전략은 권장하지 않는다.
아주 간단해 보이지만
만약 item_id의 값을 가지고 데이터를 찾기 위해서는 위 테이블을 모두 뒤져가며 찾아야 한다.
장점
- 서브 타입을 명확하게 구분하여 처리할 때 효과적
- not null 제약 조건 사용 가능
단점
- 여러 자식 테이블을 함께 조회할 때 성능 저하 (UNION SQL 필요)
- 자식 테이블을 통합해서 쿼리하기 어려움
--
코드 작성 방법 (+전략 선택 방법)
--
Item 클래스
@Entity
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
부모가 될 클래스는
abstract을 사용하여 추상 클래스로 만들어야 하위 구현 클래스마다
테이블 전략에서 Item 테이블을 생성하지 않는다.
만약 추상 클래스가 아닌 일반 클래스로 만들면
해당 Item 클래스를 독단적으로 사용할 수 있다는 의미로 그냥 DB 테이블이 생성된다.
Water, Book, Car 클래스
@Entity
public class Water extends Item {
private int ml;
}
@Entity
public class Water extends Item {
private String author;
private int page;
}
@Entity
public class Water extends Item {
private int door;
private String color;
}
위와 같이 코드를 실행하면
기본값 전략인 "단일 테이블 전략"으로 DB가 구현된다.
상속관계 매핑 방법은
부모 객체에 @Inheritance(strategy = InheritanceType.xxx) 어노테이션을 통해 선택할 수 있다.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Item {
DTYPE 추가하는 방법은
부모 객체에 @DiscriminatorColumn 어노테이션을 통해 정의할 수 있다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "CHANGE")
public class Item {
name 속성을 통해 원하는 이름으로 생성할 수 있으며
이를 생략하면 기본값인 "DTYPE" 이름으로 생성된다.
--
@MappedSuperclass
--
해당 어노테이션은 상속관계 매핑과는 관계없는 어노테이션으로
공통 매핑 정보가 필요할 때 사용되는 어노테이션이다.

객체에 공통된 속성이 존재하면
매번 같은 값을 넣기 귀찮기 때문에
그냥 공통된 속성들을 묶어서 상속을 하고 싶을 때 사용하는 어노테이션이다.
DB는 변함없이 그냥 그대로 사용된다.
즉, 객체에서만 공통된 정보를 상속해서 사용하는 것이다.
예시
일반적으로 대부분의 객체에 "생성자", "생성일자", "수정자", "수정일자" 필드(속성)가 필요하다.
이때 공통된 코드들을 따로 클래스(객체)를 만들어서 담아주고,
해당 클래스에 @MappedSuperclass 어노테이션을 붙이면 된다.
그리고 해당 필드들이 필요한 엔티티에는 해당 클래스를 extends로 상속받으면 된다.
Base 클래스
@MappedSuperclass
public abstract class Base {
private String createBy;
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
}
public class Member extends Base {
...
}
해당 방법은
상속 같은 개념보다는
그냥 공통된 필드들을 따로 모아서 필요한 사람들이 같이 사용하는 느낌으로
DB에 생성된 테이블을 보면 Member 테이블에 "생성자", "생성일자", "수정자", "수정일자" 컬럼이 같이 존재한다.
정리
- 상속관계 매핑과 관련 X
- 엔티티가 아니고 테이블과 매핑 X
- 부모 클래스를 상속받는 자식 클래스에 매핑 정보만 제공
(즉, @MappedSuperclass로 선언된 클래스는 개인적으로 조회, 검색 불가 - 직접 생성해서 사용할 일은 없으므로 추상 클래스로 만드는 것을 권장
- 테이블과 관계없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모아두는 역할
참고
@Entity로 선언한 클래스는
엔티티나 @MappedSuperclass로 지정한 클래스만 상속 가능
--
참고 및 출처
'JPA' 카테고리의 다른 글
영속성 전이 (CASCADE) (+ 고아 객체) (0) | 2025.04.03 |
---|---|
즉시 로딩 및 지연 로딩 (+ JPA의 프록시) (1) | 2025.04.02 |
연관관계 매핑 (단방향, 양방향, 1:1, 1:N, N:1, N:N) (0) | 2025.03.31 |
엔티티(Entity) 매핑 (= 객체와 DB 테이블 연결) (0) | 2025.03.30 |
영속성 관리 (내부 동작 방식) (0) | 2025.03.29 |
상속관계 매핑은 무엇일까?
관계형 DB의 상속 관계
--
자바 객체의 상속관계처럼
관계형 DB에는 상속 관계가 존재하지 않는다.
다만 "슈퍼타입", "서브타입" 관계라는 모델링 기법을 통해 객체 상속과 유사한 형태를 만들 수 있다.
즉, 상속관계 매핑은
객체의 상속 구조와 DB의 슈퍼타입, 서브타입 관계를 매핑하는 것을 의미한다.
상속관계 매핑에는 3가지 구현 방법이 존재한다.
- 조인 전략 (각 테이블로 변환)
- 단일 테이블 전략 (통합 테이블로 변환)
- 구현 클래스마다 테이블 전략 (서브타입 테이블로 변환)
조인 전략 (각 테이블로 변환)

Item 테이블을 우선 생성하고
해당 테이블 하위에 알맞은 테이블(Water, Book, Car)을 추가로 생성하며
추가로 필요할 때마다 특정 테이블을 조인하는 방식이다.
예시
Book 데이터에 접근해야 한다면
name, price는 Item 테이블에 존재하고, author, page는 Book 테이블에 존재하므로
두 테이블을 Insert 하여 가져온 다음 조인을 통해 가져온다.
여기서 어떠한 테이블과 조인할지 구분을 해야 하는데
Item 테이블에 "DTYPE"이라는 컬럼을 추가하여 "DTYPE"의 값에 조인할 테이블명 값을 정의하여
"DTYPE"이 Book이면 Book 테이블과 조인하는 식으로 사용한다.
장점
- 테이블 정규화
- 외래 키 참조 무결성 제약조건 활용 가능
- 저장공간 효율화
단점
- 조회 시 조인을 많이 사용하여 성능 저하
- 조회 쿼리가 복잡
- 데이터 저장 시 INSERT SQL문을 2번 호출
단일 테이블 전략 (통합 테이블로 변환)

그냥 하나의 테이블로 모두 합치는 방법으로
여기서도 "DTYPE" 컬럼을 이용하여 현재 어떤 테이블인지 정해서 사용한다.
(DTYPE이 Book이면 해당 테이블은 Book으로 사용)
장점
- 조인이 필요 없어 일반적으로 조회 성능이 빠름
- 조회 쿼리가 단순
단점
- 자식 엔티티가 매핑한 컬럼은 모두 null 허용
- 단일 테이블에 모든 것을 저장하므로 테이블이 커짐 (상황에 따라 조회 성능 저하)
구현 클래스마다 테이블 전략 (서브타입 테이블로 변환)

공통으로 사용하는 데이터를 각 테이블에 모두 넣어주는 방법으로
Item 테이블을 만들지 않고 각 테이블에 모두 할당한다.
해당 전략은 권장하지 않는다.
아주 간단해 보이지만
만약 item_id의 값을 가지고 데이터를 찾기 위해서는 위 테이블을 모두 뒤져가며 찾아야 한다.
장점
- 서브 타입을 명확하게 구분하여 처리할 때 효과적
- not null 제약 조건 사용 가능
단점
- 여러 자식 테이블을 함께 조회할 때 성능 저하 (UNION SQL 필요)
- 자식 테이블을 통합해서 쿼리하기 어려움
--
코드 작성 방법 (+전략 선택 방법)
--
Item 클래스
@Entity
public abstract class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
부모가 될 클래스는
abstract을 사용하여 추상 클래스로 만들어야 하위 구현 클래스마다
테이블 전략에서 Item 테이블을 생성하지 않는다.
만약 추상 클래스가 아닌 일반 클래스로 만들면
해당 Item 클래스를 독단적으로 사용할 수 있다는 의미로 그냥 DB 테이블이 생성된다.
Water, Book, Car 클래스
@Entity
public class Water extends Item {
private int ml;
}
@Entity
public class Water extends Item {
private String author;
private int page;
}
@Entity
public class Water extends Item {
private int door;
private String color;
}
위와 같이 코드를 실행하면
기본값 전략인 "단일 테이블 전략"으로 DB가 구현된다.
상속관계 매핑 방법은
부모 객체에 @Inheritance(strategy = InheritanceType.xxx) 어노테이션을 통해 선택할 수 있다.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Item {
DTYPE 추가하는 방법은
부모 객체에 @DiscriminatorColumn 어노테이션을 통해 정의할 수 있다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "CHANGE")
public class Item {
name 속성을 통해 원하는 이름으로 생성할 수 있으며
이를 생략하면 기본값인 "DTYPE" 이름으로 생성된다.
--
@MappedSuperclass
--
해당 어노테이션은 상속관계 매핑과는 관계없는 어노테이션으로
공통 매핑 정보가 필요할 때 사용되는 어노테이션이다.

객체에 공통된 속성이 존재하면
매번 같은 값을 넣기 귀찮기 때문에
그냥 공통된 속성들을 묶어서 상속을 하고 싶을 때 사용하는 어노테이션이다.
DB는 변함없이 그냥 그대로 사용된다.
즉, 객체에서만 공통된 정보를 상속해서 사용하는 것이다.
예시
일반적으로 대부분의 객체에 "생성자", "생성일자", "수정자", "수정일자" 필드(속성)가 필요하다.
이때 공통된 코드들을 따로 클래스(객체)를 만들어서 담아주고,
해당 클래스에 @MappedSuperclass 어노테이션을 붙이면 된다.
그리고 해당 필드들이 필요한 엔티티에는 해당 클래스를 extends로 상속받으면 된다.
Base 클래스
@MappedSuperclass
public abstract class Base {
private String createBy;
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
}
public class Member extends Base {
...
}
해당 방법은
상속 같은 개념보다는
그냥 공통된 필드들을 따로 모아서 필요한 사람들이 같이 사용하는 느낌으로
DB에 생성된 테이블을 보면 Member 테이블에 "생성자", "생성일자", "수정자", "수정일자" 컬럼이 같이 존재한다.
정리
- 상속관계 매핑과 관련 X
- 엔티티가 아니고 테이블과 매핑 X
- 부모 클래스를 상속받는 자식 클래스에 매핑 정보만 제공
(즉, @MappedSuperclass로 선언된 클래스는 개인적으로 조회, 검색 불가 - 직접 생성해서 사용할 일은 없으므로 추상 클래스로 만드는 것을 권장
- 테이블과 관계없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모아두는 역할
참고
@Entity로 선언한 클래스는
엔티티나 @MappedSuperclass로 지정한 클래스만 상속 가능
--
참고 및 출처
'JPA' 카테고리의 다른 글
영속성 전이 (CASCADE) (+ 고아 객체) (0) | 2025.04.03 |
---|---|
즉시 로딩 및 지연 로딩 (+ JPA의 프록시) (1) | 2025.04.02 |
연관관계 매핑 (단방향, 양방향, 1:1, 1:N, N:1, N:N) (0) | 2025.03.31 |
엔티티(Entity) 매핑 (= 객체와 DB 테이블 연결) (0) | 2025.03.30 |
영속성 관리 (내부 동작 방식) (0) | 2025.03.29 |