상속관계 맵핑

객체지향의 상속이라는 개념은 RDB에는 없고 Super Type / Sub Type 관계라는 모델링 기법이 가장 유사해 상속관계를 이 Super/Sub type관계로 맵핑하는 방법으로는 크게 3가지가 존재한다.

1. 조인 전략

테이블을 각각 만들고 조회할때 조인을 사용하는 방법

부모클래스에 @Inheritance(strategy = InheritanceType.JOINED)를 통해 부모클래스임을 명시하고 맵핑전략을 지정해주어야 한다. @DiscriminatorColumn(name = "DTYPE")을 명시함으로써 자식 테이블을 구분하기 위한 DTYPE 필드를 지정한다.

자식 클래스들은 @DiscriminationValue()를 통해 엔티티를 저장할 때 구분 컬렘에 입력할 값을 지정할 수 있다. 자식클래스의 저장되는 PK이자 FK는 부모 테이블의 ID명을 그대로 사용하는데 @PrimaryKeyJoinColumn을 이용해 컬럼명을 변경할 수 있다.

특징

JPA 표준 명세는 구분 컬럼을 사용하도록 하지만 몇몇 구현체는 이 구분 컬럼이 없어도 동작한다.

장점

  1. 테이블이 정규화된다.

  2. 외래키 참조 무결정 제약조건을 활용할 수 있다.

  3. 저장공간을 효율적으로 사용한다.

단점

  1. 조회시 많은 조인으로 성능 저하 우려

  2. 복잡한 조회 쿼리

  3. 데이터를 등록할 Insert SQL을 두번 실행한다.

2. 단일 테이블 전략

테이블을 하나만 사용해 통합하는 방법으로 각 자식의 필드들와 부모 엔티티의 필드가 하나의 테이블로 합쳐진 방법이다. 그렇기 때문에 자식 엔티티가 매핑한 컬럼들은 모두 null을 허용해야 하고 구분 컬럼(DiscriminatorValue)을 필수로 사용해야 한다. (한개의 자식엔티티를 저장하려고 하면, 그 외의 자식 엔티티 필드값은 당연히 null이기 되기 때문에 null이 허용되어야 한다.)

부모 클래스에 Inheritance(strategy = InheritanceType.SINGLE_TYPE)으로 지정하면 사용할 수 있다.

장점

  1. 조인이 필요없어 조회성능이 빠르다.

  2. 조회 쿼리가 단순하다.

단점

  1. 자식 엔티티가 맵핑한 컬럼들은 모두 null을 허용해야한다.

  2. 테이블의 크기가 커지기 때문에 오히려 성능이 느려질 수 있다.

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

서브타입 마다 하나의 테이블을 만드는 방법으로 Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)를 지정하면 이 전략을 사용할 수 있다.

자식엔티티마다 테이블을 만드는 방법으로 구분 컬럼을 사용하지 않아도 되지만 일반적으로 추천하지 않는 방법이다.

장점

  1. 서브타입을 구분해서 처리할때 효과적

  2. not null 을 사용할 수 있다.

단점

  1. 여러 자식 테이블을 함께 조회할때 성능이 느리다.

  2. 자식 테이블을 통합해서 쿼리하기 힘들다.

@MappedSuperclass

위의 3가지 전략은 부모/자식 클래스를 테이블과 맵핑했지만 @MappedSuperClass는 부모 클래스를 실제 테이블과 맵핑하고 싶지 않을때 사용한다.

  • @AttributeOverrides / @AttributeOverride : 맵핑 정보(필드) 재정의 할때 사용

  • @AssociationOverrides : 연관관계 재정의 할 때 사용


Reference

자바 ORM 표준 JPA 프로그래밍 책 (김영한 저)

Last updated