Java

[JPA(Jakarta Persistence API)] 상속관계 매핑, @MappedSuperclass

ride-dev 2024. 3. 12. 22:28

상속관계 매핑

관계형 데이터베이스는 객체의 상속관계를 지원하지 않지만,

슈퍼타입 서브타입 관계가 그나마 유사하기 때문에 이를 상속관계 매핑에 사용합니다.

(객체의 상속 구조와 DB의 슈퍼타입 서브타입 관계를 매핑하는 것으로 상속관계 매핑을 사용합니다)

 

조인 전략을 사용하여 각각 테이블로 변환할 수 있습니다.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int price;
}

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

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

 

ITEM엔티티의 @DiscriminatorColumn으로 생성된 DTYPE 컬럼에는 @DiscriminatorValue에 선언한 값이 삽입됩니다.

테이블이 정규화되어 있기 때문에 저장공간을 효율적으로 사용할 수 있지만,

조회 시 조인을 많이 사용하고, 조회 쿼리가 복잡하며 데이터 저장 시 INSERT문을 2회(ITEM + 하위) 호출합니다.

(관리가 복잡하지만, 조인 최적화가 가능하고 저장공간 효율성을 고려하면 이점이 많기에 정석적으로 사용합니다)

 

단일 테이블 전략을 사용하여 통합 테이블로 변환할 수 있습니다.

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

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

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

(어노테이션의 전략만 변경하면 됩니다)

조인이 필요하지 않으므로 조회 성능이 높고, 조회 쿼리가 단순하지만,

자식 엔티티가 매핑한 컬럼은 모두 null이 허용되며 테이블이 커질 수 있기 때문에,

상황에 따라 조회성능이 되려 낮아질 수 있습니다.

 

구현 클래스마다 테이블 전략을 사용하는 것으로 서브타입 테이블로 변환하는 방법을 사용할 수 있습니다.

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

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

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

(조회 시 union all을 사용하기 때문에 성능 문제가 발생할 수 있습니다)

not null 제약조건 사용이 가능하고, 서브타입을 명확히 구분해서 처리할 때 효과적이나,

자식 테이블을 통합해서 쿼리하기 어렵고, 자식 테이블을 함께 조회할 때 성능이 현저히 낮아집니다.

(일반적으로 사용하지 않는 방법입니다)

@MappedSuperclass

공통 매핑 정보가 필요할 때 사용합니다.

상속관계 매핑이 아닙니다.

엔티티가 아니며, 테이블과 매핑할 수 없습니다.

부모 클래스를 상속받는 자식 클래스에 매핑 정보만 제공합니다.

조회, 검색이 불가능합니다.

직접 생성해서 사용할 일이 없으므로 추상클래스 사용을 권장합니다.

@MappedSuperclass
public abstract class BaseEntity {
    private Long id;
    private String name;
}

@Entity
public class Member extends BaseEntity {
    private String email;
}

@Entity
public class Seller extends BaseEntity {
    private String shopname;
}

테이블과 관계가 없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모으는 역할을 합니다.

주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용합니다.

(@Entity 클래스는 엔티티나 @MappedSuperclass로 지정한 클래스만 사용가능합니다)

728x90