객체는 상속관계가 존재하지만 관계형 데이터베이스는 없다.
그러나, 슈퍼타입 서브타입 관계라는 상속과 유사한 모델링 기법이 존재한다.
이 모델링 기법을 활용하여 객체의 상속관계와 매핑할 수 있다.
어떻게?
슈퍼타입, 서브타입은 물리적으로 테이블을 구성하는 것이 아니라, 논리 모델이다.
실제 물리 모델로 구현하는 방법으로 객체의 상속을 표현할 수 있다.
조인 전략
각각 테이블로 구성하고, 하위 테이블에서 FK를 통해 매번 조인을 통해 데이터를 가져오는 방법
상위 테이블에서 어떤 테이블의 부모인지 알기 위한 타입 컬럼이 필요
장점
데이터가 정규화되어 있다.
참조 무결성 제약조건을 활용가능하다.
저장공간 효율화
단점
조인을 많이 사용, 성능 저하
조회 쿼리가 복잡함
INSERT 쿼리가 2번 호출
장단점이 존재하나 객체의 상속과 가장 유사하고, 성능 문제를 고려하여 구현 시, 그 정도가 미미하여 가장 정석적으로 사용됨
단일 테이블 전략
모든 데이터를 하나의 테이블에 저장
열마다 타입 컬럼의 값을 통해 어느 객체에 매핑할 지 판단
장점
조인이 필요 없어 성능이 가장 좋음
조회 쿼리가 단순함
단점
자식 엔티티와 관련된 컬럼은 모두 nullable 이여야함
테이블이 커질 수 있고, 상황에 따라 조회 성능이 오히려 느려질 수 있음 (임계점을 넘으면 타 전략에 비해 느려지지만 그럴 일이 별로 없음)
구현 클래스마다 테이블 전략
중복되는 데이터를 따로 테이블로 빼는 것이 아니라, 하위 테이블에 중복되도록 컬럼을 추가하는 방법
각각 테이블마다 PK가 존재하게 되므로, 상위 클래스로 객체를 찾으려하면 모든 테이블에 쿼리를 날린다
장점
서브 타입을 명확하게 구분해서 처리해야할 때 효과적
not null 제약조건 사용 가능
단점
여러 자식 테이블을 함께 조회 시 성능이 느림 (UNION SQL)
자식 테이블을 통합해서 쿼리하기 어려움
DBA와 ORM 전문가가 둘다 싫어하는 전략
JPA 에서는 세 방법 모두 객체에 매핑이 가능하다.
조인전략 선택하기
부모 클래스에서 @Inheritance 어노테이션 사용
strategy 속성 값을 설정하여 전략을 지정할 수 있음
JOINED: 조인 전략
SINGLE_TABLE: 단일 테이블 전략, 기본값
TABLE_PER_CLASS: 구현 클래스마다 테이블 전략
타입 컬럼 지정하기
부모 클래스에서 @DiscriminatorColumn 어노테이션 사용
하위 클래스의 엔티티명이 자동으로 DB에 상위 테이블에 저장
저장될 컬럼명을 name 속성을 통해 지정할 수 있음
하위 클래스의 엔티티명이 아닌 다른 값으로 저장하고 싶다면 하위 클래스에서 @DiscriminatorValue 어노테이션을 통해 지정할 수 있음
단일 테이블 전략의 경우, 타입 컬럼이 존재하지 않으면 해당 row가 어느 데이터인지 알 수 없으므로 따로 지정해주지 않아도 생성됨
추가.
모든 게시물에는 작성자와 작성 시간, 수정 시간을 기록해야 한다는 요구사항이 있을 때, 모든 게시물 관련 객체에 해당하는 필드들을 추가해야할까?
-> @MappedSuperclass 어노테이션을 사용하자.
공통 정보들을 하나의 클래스로 묶고 @MappedSuperclass 를 적용한다.
공통 정보들을 사용할 클래스들에서 해당 클래스를 상속한다.
이후 상속한 모든 하위 객체와 매핑되는 테이블에 공통정보들이 들어가고, 객체에서도 자유롭게 사용할 수 있다.
참고.
엔티티 객체는 다른 엔티티나 @MappedSuperclass 객체만 상속받을 수 있다.