[김영한 - JPA 기본] #7 고급매핑
핵심 요약
JOINED : 조인전략
- 사실상 이게 메인
- 중요한 도메인에 해당 !
@Inheritance(strategy = InheritanceType.JOINED)
SINGLE_TABLE : 단일
- 가볍게 가져갈때
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
- TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
- worst
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
상속 관계 매핑
기본적으로 관계형 DB는 상속관계가 없다
그러나 슈퍼타입, 서브타입 모델링 기법은 객체 상속과 유사하다객체의 상속구조와 DB의 슈퍼, 서브타입 관계를 매핑한다
주요 어노테이션
// 상속 관계 전략 설정
@Inheritance(strategy=InheritanceType.XXX)
• JOINED : 조인 전략
• SINGLE_TABLE : 단일 테이블 전략
• TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
// JOINED, SINGLE_TABLE 선택시 구분자 컬럼명
@DiscriminatorColumn(name=“DTYPE”)
// 컬럼의 값 명, default는 Entity 명이다
// 예) Album 엔티티는 Album 으로 값이 설정됨
@DiscriminatorValue(“XXX”)
실제 매핑 예시
@Entity
@DiscriminatorValue("A") // 이런 약어는 지양하는게 좋다
public class Album extends Item {
private String artist;
...
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "D_COL")
abstract public class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
...
조인전략
@Inheritance(strategy = InheritanceType.JOINED)
장점
- 테이블들이 자연스럽게 정규화됨
- 외래키 참조 무결성 제약조건 활용 가능
- ID로 서로 연결하여 값을 가져올 수 있다
- 상속관계를 이용함으로써 저장공간 효율화
단점
- 조회시 조인을 많이 사용, 성능 저하
그러나 인덱스 등을 이용해서 최적화 가능 !
- 조회 쿼리가 복잡함
우리가 쿼리를 작성하지 않아 !!
- 데이터 저장시 INSERT 쿼리 2번 호출
- 조회시 조인을 많이 사용, 성능 저하
단일 테이블 전략
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
장점
- 조인이 필요 없으므로 일반적으로 조회 성능이 빠름
- 조회 쿼리가 단순함
단점
- 자식 엔티티가 매핑한 컬럼은 모두 null 허용
예를들어 Album 객체를 테이블에 넣을시 Movie, Book 등의 컬럼 정보는 당연히
null
이다
- 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다. 상황에 따라서 조회 성능이 오히려 느려질 수 있다
- 자식 엔티티가 매핑한 컬럼은 모두 null 허용
구현 클래스마다 테이블 전략
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
이 전략은 DB 설계자와 ORM 전문가 모두 다 추천하지 않는다
- 장점
- 서브 타입을 명확하게 구분해서 처리할 때 효과적
not null
제약 조건 사용가능
- 단점
- 여러 자식 테이블을 함꼐 조회할 때 성능이 느림 (UNION SQL 필요)
예시에 있는 Item의 Price 를 보고 싶을 떄 , 즉 가격을 정산할 떄 모든 테이블을 긁어 모은다
- 자식 테이블을 통합해서 쿼리하기 어려움
- 여러 자식 테이블을 함꼐 조회할 때 성능이 느림 (UNION SQL 필요)
@MappedSuperclass
- 공통 매핑 정보가 필요할 때 사용한다
- 엔티티가 공통으로 사용하는 매핑 정보를 모음
- 상속관계 매핑과는 완전히 다른 개념이다 !
- 엔티티가 아니며 따라서 테이블과 매핑되는 개념도 아니다
- 테이블이 별도로 생성되는 개념이 아니다
따라서 당연히 조회, 검색이 불가하다em.find(BaseEntity)
불가
- 테이블이 별도로 생성되는 개념이 아니다
- 부모 클래스를 상속 받는 자식에 매핑 정보만을 제공한다
직접 생성해서 사용하는 개념이 아니므로 추상 클래스
abstract
를 사용하자 !주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 적용할 때 사용
- 참고:
@Entity
클래스는 엔티티나@MappedSuperclass
로 지정한 클래스만 상속 가능하다
현재날짜, 현재 사용자의 세션 등의 정보를 어노테이션으로 자동으로 넣는 것도 가능하다 (이후 강의)
예제 코드
@Entity
public class Member extends BaseEntity {
...
}
@MappedSuperclass
public class BaseEntity {
@Column(name = "CREATED_BY")
private String createdBy;
@Column(name = "CREATED_AT")
private LocalDateTime createdAt;
@Column(name = "LAST_MODIFIED_BY")
private String lastModifiedBy;
@Column(name = "LAST_MODIFIED_AT")
private LocalDateTime lastModifiedAt;
}