고급 매핑


상속관계 매핑


객체의 상속구조DB의 슈퍼타입-서브타입 관계 를 매핑

• 관계형 데이터베이스는 상속 관계가 없다.

• 슈퍼타입-서브타입 관계라는 논리 모델링 기법이 객체 상속과 유사하다.


슈퍼타입-서브타입 논리모델을 실제 물리 모델로 구현하는 방법은 아래와 같다.

방법전략주요 어노테이션
각각 테이블로 변환조인 전략JOINED
통합 테이블로 변환단일 테이블 생성 전략(default)SINGLE_TABLE
서브타입 테이블로 변환구현 클래스마다 테이블 생성 전략TABLE_PER_CLASS


조인 전략


예시 코드

위 이미지와 같이 DB에 ITEM, ALBUM, MOVIE, BOOK 테이블이 생성된다.

그리고 이 테이블들은 외래키인 ITEM_ID를 통해서 조인 전략 이 수행된다.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "ITEM_TYPE")
public class Item {

    @Id
    @GeneratedValue
    private Long id;

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


DB 저장, 조회

▷ 저장

Movie movie = new Movie();
movie.setDirector("감독A");
movie.setActor("배우A");
movie.setName("영화A");
movie.setPrice(10000);
em.persist(movie);

DB 테이블에는 아래와 같이 데이터가 들어가게 된다. ID 컬럼이 외래키가 된다.

ITEM_TYPEIDNAMEPRICE
M1영화A10000
ACTORDIRECTORID
배우A감독A1


▷ 조회

내부적으로 조인을 하여 쿼리를 날린다.

Movie findMovie = em.find(Movie.class, movie.getId());
select
    movie0_.id as id1_5_0_,
    movie0_1_.name as name2_5_0_,
    movie0_1_.price as price3_5_0_,
    movie0_.actor as actor1_8_0_,
    movie0_.director as director2_8_0_ 
from
    Movie movie0_ 
inner join ItemPrac movie0_1_ 
    on movie0_.id=movie0_1_.id 
where
    movie0_.id=?


어노테이션 설명

어노테이션설명비고
@Inheritance(strategy = InheritanceType.JOINED)JOIN전략 
@DiscriminatorColumn(name = “ITEM_TYPE”)DTYPE 컬럼 생성있는게 좋다.
@DiscriminatorValue(“M”)DTYPE 컬럼에 들어갈 엔티티 이름의 별칭 


장단점

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


단일 테이블 전략


예시 코드

위 이미지와 같이 하나의 ITEM이라는 테이블에 모든 컬럼이 다 들어간다.

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

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private int price;
}
  • @DiscriminatorColumn 없어도 DTYPE 컬럼 생성


장단점

장점단점
조인이 필요 없으므로 일반적으로 조회 성능이 빠름자식 엔티티가 매핑한 컬럼은 모두 Null허용
조회 쿼리가 단순단일 테이블에 모든 것을 저장하므로 테이블이 커짐(성능 저하-캐바캐)


구현 클래스마다 테이블 전략

이 전략은 데이터베이스 설계자와 ORM 전문가 둘 다 추천X


예시 코드

각각 ALBUM, MOVIE, BOOK 테이블이 생성이 되는데, 부모 클래스의 필드(id,name,price)가

하위 클래스에 모두 중복으로 들어가게 된다.

그리고 Item을 추상클래스로 정의했기 때문에 ITEM 테이블이 생성되지 않는다.

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

    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private int price;
}


장단점

장점단점
서브 타입을 명확하게 구분해서 처리할 때 효과적여러 자식 테이블을 함께 조회할 때 성능이 느림(UNION SQL 필요)
not null 제약조건 사용 가능자식 테이블을 통합해서 쿼리하기 어려움

이 전략은 데이터를 삽입할 때 문제가 되지 않는다. 그런데 Item 타입으로 조회할 때,

UNION ALL로 Item을 상속 받은 모든 테이블을 조회한다. 따라서 성능 저하가 초래된다.


정리


기본적으로 JOIN전략단일 테이블 전략을 생각하면서 개발을 하고 DBA와 고민해서

선택을 하는게 좋다. 추천은 기본적으론 JOIN전략 을 베이스로 가져가고,

만약 테이블이 단순하고 확장 가능성이 없다고 판단되면 단일 테이블 전략을 가져가는게 좋다.

어떤 걸 선택하든 장단점은 있기 때문에 상황에 맞춰 적절한 전략을 선택해야 한다.