티스토리 뷰

JPA에서 연관관계를 매핑하는 관계로 1:1, 1:N, N:1, N:M 등과 같은 다양한 연관관계 매핑이 존재합니다. 일반적인 엔티티와 엔티티 사이의 매핑을 나타내는데, 객체지향 프로그래밍에서는 상속관계가 존재합니다. 그럼 엔티티 사이에도 상속관계가 존재할 수 있을까? 라는 궁금증이 생깁니다. 결론적으로 관계형 데이터베이스는 상속 관계가 존재하지만, 슈퍼타입 서브타입 관계라는 모델링 기법이 존재합니다.

이 기법이 객체 상속과 유사한 기법이라고 할 수 있습니다. 즉, 공통된 데이터를 슈퍼타입에 남기고 객체가 가지고 있는 특별한 속성들만 서브타입에 남겨주는 구조를 가지고 있습니다.

JPA에서는 상속관계 매핑을 지원하는데, 객체의 상속 구조와 데이터베이스의 슈퍼타입, 서브타입 관계를 매핑한다고 할 수 있습니다. 쉽게 말해 슈퍼타입, 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법입니다. BaseEntity라는 엔티티를 만들어 슈퍼타입으로 Member, Seller 엔티티는 서브타입으로 매핑합니다. 여기서 슈퍼타입, 서브타입 논리 모델을 실제 물리모델로 구현하는 방법은 3가지가 존재합니다.

1. 각각 테이블로 변환 -> JOIN 전략
2. 통합 테이블로 변환 -> 단일 테이블 전략
3. 서브타입 테이블로 변환 -> 구현 클래스마다 테이블 전략

@Inheritance(strategy=InheritanceType.xxxx)
JOINED: 조인 전략
SINGLE_TABLE: 단일 테이블 전략 (default)
TABLE_PER_CLASS: 구현 클래스마다 테이블 전략 

JOIN 전략

조인 전략입니다. Base Entity와 Sub Entity로 테이블을 나누는 구조입니다. Base Entity에 @DiscriminatorColumn(name="DTYPE")과 Sub Entity에 @DiscriminatorValue("XXX) 어노테이션을 이용해 DTYPE을 설정할 수 있습니다. @DiscriminatorValue를 따로 설정하지 않으면 해당 클래스의 첫번째 문자로 저장됩니다. BOOK -> "B".

 

장점

테이블 정규화를 할 수 있습니다. 또 외래 키 참조 무결성 제약조건을 활용할 수 있고, 저장공간을 효율화할 수 있습니다.

-> 정규화란 테이블 간에 중복된 데이터를 허용하지 않는다는 것입니다. 중복된 데이터를 허용하지 않음으로써 무결성(Integrity)를 유지할 수 있고, DB의 저장 용량 역시 줄일 수 있습니다.

 

 

단점

조회 시 조인을 많이 사용하므로 성능저하가 발생할 수 있습니다. 조회 쿼리가 복잡하고, 데이터 저장시 Base, Sub 로 INSERT 쿼리가 각 1번씩 총 2번 호출됩니다.


단일 테이블 전략

단일 테이블 전략은 조인 전략과 달리 하나의 테이블에 모든 객체 속성을 다 집어넣는 구조입니다. 마찬가지로 DTYPE을 통해 구분할 수 있습니다.

 

장점

조인이 필요 없으므로 일반적으로 조회 성능이 빠릅니다. 그러므로 조인 전략과는 달리 조회 쿼리가 단순합니다.

 

단점

Sub Entity(자식 엔티티)가 매핑한 컬럼은 모두 null 값을 허용합니다. 만약 Book 객체를 생성하는 경우 artist, director, actor 컬럼은 모두 null값으로 저장됩니다. 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있고 상황에 따라서 조회 성능이 오히려 느려질 수 있습니다.

 


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

구현 클래스마다 테이블 전략은 한 테이블 마다 PK와 속성을 집어넣는 구조입니다.

 

장점

서브 타입을 명확하게 구분해서 처리할 때 효과적이고, not null 제약조건을 사용할 수 있습니다.

 

단점

UNION SQL이 필요하기 때문에 여러 자식 테이블을 함께 조회할 때 성능이 느림니다. 자식 테이블을 통합해서 쿼리하기 어렵습니다. 그러므로 DBA와 ORM 전문가 분들이 추천하지 않는 전략입니다.

 


@MappedSuperClass

상속관계가 아닌 공통 매핑 정보가 필요할 때 사용하는 어노테이션입니다. 상속관계 매핑이 되지 않으며, 엔티티의 역할을 하지 않고 테이블과 매핑이 되지 않는 클래스입니다. 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공합니다.

조회, 검색(em.find(BaseEntity))이 불가하며, 직접 객체를 생성해서 사용할 일이 없으므로 추상 클래스를 권장합니다.

 

즉, 테이블과 관계가 없고 단순히 엔티티가 공통으로 사용하는 매핑정보를 모으는 역할입니다. 주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용합니다.

 

댓글