JPA 상속관계 매핑에 대해 알아보자

상속관계 매핑이란

: 먼저 데이터 베이스는 원래는 상속 관계를 지원하지 않아!! But 슈퍼타입-서브타입이라는 모델링 기법이 존재하고 이녀석이 객체 상속과 비슷하게 생겼어!! 이를 이용해서 상속관계를 나타내보자!! 이렇게 된거지

그래서 상속관계 매핑은 객체의 상속구조와 데이터베이스의 슈퍼타입-서브타입 관계를 매핑하는거야!

여기에는 크게 3가지 전략이 있어

  1. 조인전략
  2. 단일 테이블 전략
  3. 구현 클래스마다 테이블 전략

이 3가지에 대해 알아볼거야. 참고로 어떤 전략을 쓰던 jpa에서는 상관없이 전부 매핑이 가능해.

그럼 매핑하려면 어떻게 해야하냐?

@Inheritance(strategy = InheritanceType.TYPENAME) 어노테이션을 사용하면 돼!!




조인전략 (@Inheritance(strategy = InheritanceType.JOINED))

: 이녀석은 쉽게 생각하면 각각 테이블로 변환한다고 생각하면 돼. 무슨말이냐?

위 그림처럼 된다고 볼 수 있어. JPA를 통해 특정 엔티티를 조회하려 한다면 데이터베이스에서는 조인을 통해 사용자가 원하는 데이터를 만들어주겠지.

위에 ITEM 테이블을 보면 DTYPE이라는 컬럼이 있어. 이 녀석을 통해 현재 ITEM_ID가 어떤 하위 타입이랑(ALBUM, MOVIE, BOOK) 관련 있는지를 쉽게 알아볼 수 있는거지.

저 DTYPE은 그냥 만들어지진 않고 어노테이션을 통해 설정을 해줘야해!! (참고로 운영까지 생각하면 만들어두는게 좋아!!)

상위타입에 DiscriminatorColumn을 붙이면 돼!! default는 DTYPE이란 형태로 만들어져!!

만약 바꾸고싶다?? (name = “blabla”) 이렇게 속성을 주면 돼!!


조인전략 장점

  • 위 그림에서도 보이듯이 테이블이 정규화가 되어있고 딱 필요한 공간만 딱딱 쓰는 구조야!
  • 외래 키 참조 무결성 제약조건을 활용할 수 있어

조인전략 단점

  • 조회할 때 조인을 많이 사용해 → 서능 저하 (조회 쿼리가 복잡해)
  • 데이터 저장시 insert sql 2번 날려!!

but!! 위의 단점도 크게 신경쓸 만큼 치명적인 것이 아니고 장점이 많은 전략이라 대부분 보통 조인전략으로 하는 것을 생각하고 있으면 돼!!




단일 테이블 전략(@Inheritance(strategy = InheritanceType.SINGLE_TABLE))

: 이녀석은 쉽게 생각하면 통합테이블로 변환한다라고 생각하면 돼!

이렇게 말이야!!

결국 슈퍼타입 테이블이 서브타입 테이블의 모든 필드를 가지고 있는 형태야!!

단순하고 빠르기에 데이터가 많지 않으면 이 전략이 좋을 수 있어!!

아까 위의 조인전략에서는

@DiscriminatorColumn 어노테이션을 사용함으로써 DTYPE 컬럼을 만들어 주었으나 현재 단일테이블 전략에서는 붙여주지 않아도 DTYPE 필드가 만들어져!!

WHY?? 조인전략에서는 사실 DTYPE 컬럼이 없어도 데이터를 찾아올 수 있지만 단일 테이블 전략에서는 DTYPE 컬럼이 없다면 데이터를 구분할 수가 없어지자나!! 무조건 구분할 수 있는 컬럼이 필요하기에 @DiscriminatorColumn을 붙이지 않아도 자동으로 생성되게 되있는거야!!


단일 테이블 전략 장점

  • 조인이 필요없어 → 조회 성능이 빨라 (쿼리도 단순)

단일 테이블 전략 단점

  • 자식 엔티티가 매핑한 컬름은 모두 null이 허용되버려
  • 단일테이블에 저장하기에 서브타입 애들이 너무 많아져서 테이블이 비정상적으로 커질 경우 오히려 성능 저하가 올 수 있다




구현 클래스마다 테이블 전략(@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS))

: 이녀석은 쉽게 생각하면 서브타입 테이블로 변환한다고 생각하면 돼!

이렇게 말이야!!

얘는 그냥 쓰면 안돼!! 🤑🤑🤑 아래 단점을 봐봐…


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

  • 서브타입을 명확하게 구분할 수 있어
  • 완전히 분리되어있기에 각 서브타입 애들이 (ALBUM, MOVIE, BOOK) 특정 컬럼에 not null 제약 조건을 걸 수 있어

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

  • 변경이 일어났을 때를 생각하면 다~~ 뜯어 고쳐야해.. ㅠㅠ
  • 조회(상위타입으로)할 때 union을 무진장 사용하게 되는거야… → 성능 저하
  • 자식 테이블을 통합해서 쿼리를 날리기가 어려워…




@MappedSuperclass

: 자아 위에 여러 상속관계 매핑 전략들을 봤는데 보면서 그냥 단순하게 정말 특정 속성을 그대로 가져와서 쓰고싶기만 한 경우에도 저렇게 해야하는건가..? 라는 걱정이 들 수 있지!

그래서 있는 놈이 @MappedSuperclass 야!!

얘는 상속관계 매핑이 아니야!!
엔티티도 아니야!! 그렇기에 테이블과 매핑되지도 않겠지!!
단순히 부모 클래스를 상속받는 자식 클래스에 매핑 정보만 제공해줘.

이 부모 클래스를 BaseEntity라고 표현할 때 em.find(BaseEntity)이런 건 불가능해!!

당연히 엔티티가 아니닝께 조회 검색 이런건 안되는게 맞는거지!!

직접 생성해서 사용할 일이 없으니까 혹~~여나 누가 실수할 수도 있으니 추상클래스로 만들기를 권장해

  • 테이블과 관계 없고 단순히 엔티티들이 공통으로 사용하는 매핑정보를 모아주는 역할을 하는거야
  • 주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용해
  • 이건 참고사항!! @Entity 클래스는 엔티티나 @MappedSuperclass로 지정한 클래스만 상속가능해!!







https://www.inflearn.com/course/ORM-JPA-Basic

https://ict-nroo.tistory.com/128

https://velog.io/@ljinsk3/JPA-상속-관계-매핑