상속관계 매핑이란
: 먼저 데이터 베이스는 원래는 상속 관계를 지원하지 않아!! But 슈퍼타입-서브타입이라는 모델링 기법이 존재하고 이녀석이 객체 상속과 비슷하게 생겼어!! 이를 이용해서 상속관계를 나타내보자!! 이렇게 된거지
그래서 상속관계 매핑은 객체의 상속구조와 데이터베이스의 슈퍼타입-서브타입 관계를 매핑하는거야!
여기에는 크게 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로 지정한 클래스만 상속가능해!!