상속관계 매핑 전략

Posted by sJun on November 05, 2020 ·

RDBMS는 상속 관계가 없습니다.

슈퍼타입 - 서브타입 관계가 객체의 상속과 비슷할 뿐이죠.

JPA의 상속관계 매핑은

슈퍼타입 - 서프타입과 객체 상속의 구조를 서로 매핑시켜주는 작업입니다.

상속관계 매핑 전략에는 3가지가 있습니다.


@Inheritance(strategy = InheritanceType.JOINED)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

erd

Item과 각각의 서브 타입이 묶여있는 최초의 테이블 구조입니다.

JOINED 전략을 사용하면 다음 그림과 같이 됩니다.

erd2

Item 테이블 내부의 item_id를 통해서 연결되어 있습니다.

만약 Book 테이블에 데이터를 넣는다면 product_name과 product_price는 Item 테이블에, author과 isbn은 Book 테이블에 따로 저장됩니다.

데이터를 넣을 때 INSERT 문이 두번 나가겠네요.

조회는 PK가 서로 같으므로 JOIN으로 불러올 수 있습니다.

다만 주의하셔야 될 것은 JOIN 전략을 선택했을 때는 DTYPE를 명시해주는 것이 좋습니다.

@DiscriminatorColumn

위의 설정정보로 DTYPE를 명시할 수 있습니다.

DTYPE는 테이블에 데이터를 저장했을 때 서브 타입 엔티티의 이름이 들어가게 됩니다.

@Transactional
@SpringBootTest
class MemberRepositoryTest {

    @PersistenceContext
    EntityManager em;

    @Test
    @Rollback(value = false)
    void o(){
        Book book = new Book();
        book.setAuthor("kim");
        book.setIsbn("1111");
        book.setName("JPA");
        book.setPrice(10000);

        em.persist(book);
    }
}

다음 테스트 코드를 입력했을 때 h2 DB의 결과입니다.

ca

보시다시피 DTYPE에 Book 엔티티의 이름값이 들어간 걸 볼 수 있죠.

DTYPE는 흩어져있는 서브 타입들 중 어느 서브 타입이 들어간 것인지 빠르게 알기 위해서라도 명시해주는 것이 좋습니다.


두번째는 싱글 테이블 전략입니다.

싱글 테이블은 특별한게 없습니다. 흩어져 있는 테이블 전부를 SINGLE TABLE로 만듭니다.

erd3

싱글 테이블의 경우는 DTYPE를 생략할 수 없습니다. 이유는 내가 어느 엔티티의 이름을 넣었는 지 알 수 있는 방법이 없기 때문에 DYPTE 값이 무조건 채워지게 됩니다.


조인 전략과 싱글 테이블 전략은 각각 장단점이 있습니다.

JOINED 전략

장점 : 테이블이 정규화, 외래키 참조 무결성 제약조건 활용가능

단점 : 조인을 사용하다보니 조회 쿼리가 복잡해짐

SINGLE_TABLE 전략

장점 : 단일 테이블에 모든 것을 관리하므로 조회가 간단

단점 : 자식 엔티티가 매핑한 컬럼은 Null 허용 (Book 엔티티에 데이터를 이미 넣은 상태에서 Computer나 Dress 테이블은 Null 값이 들어갈 수 밖에 없습니다.)

단일 테이블에 모든 것을 저장하므로 테이블의 크키가 커짐.


TABLE_PER_CLASS 의 경우는 Item 테이블의 모든 데이터 필드들을 서브 타입에게 내려준다고 보면 됩니다.

예를들어 BOOK, COMPUTER, DRESS 테이블 전부가 각각 item 테이블 내부의 ITEM_ID, name, price 내려받습니다. 이렇게 내려주는 대신 Item 테이블은 없어집니다.

이 전략은.. 서브타입이 명확해진다는 장점이 있지만 여러 자식 객체들을 불러오려면 UNION 쿼리문을 통해서 불러오기 때문에 조회 성능이 상당히 안 좋아집니다.

FK로 연결된 부분이 없으므로 조회를 하려면 흩어진 테이블들을 합칠 수 밖에 없겠죠.

그리고 이러한 테이블들을 한 번에 관리하기도 어려워서 잘 쓰이지 않는 전략입니다.