자바 ORM 표준 JPA 프로그래밍 섹션7. 고급매핑
상속관계 매핑
관계형 DB는 상속관계가 없다. 대신 슈퍼타입, 서브타입 관계라는 모델링 기법이 있는데 이가 객체 상속 관계와 유사하다. 따라서 상속 관계 매핑은 객체의 상속 구조와 DB의 슈퍼타입, 서브타입 관계를 매핑하는 것이다.
주요 어노테이션
- @Inheritance(strategy=InheritanceType.XXX)
- JOINED: 조인 전략
- SINGLE_TABLE: 단일 테이블 전략
- TABLE_PER_CLASS: 구현 클래스마다 테이블 전략
- @DiscriminatorColumn(name=“DTYPE”)
- 부모 입장에서 DTYPE의 기본값은 자식의 Entity명이다.
- @DiscriminatorValue(“XXX”)
- 자식 입장에서 자신의 DTYPE 이름을 지정할 수 있다.
슈퍼타입, 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법은 아래와 같이 3가지가 있다. 아래 3가지 모두 JPA에서 매핑을 지원한다.
1. 조인 전략
각각 테이블로 변환하여 조인하는 전략이다. 이때 부모 역할을 하는 테이블에 DTYPE과 같이 구분 가능한 컬럼을 둔다.
아래와 같이 구현할 수 있다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public class Item {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
@Entity
public class Album extends Item {
private String artist;
}
@Entity
public class Book extends Item{
private String author;
private String isbn;
}
@Entity
public class Movie extends Item{
private String director;
private String actor;
}
- 장점
- 테이블의 정규화
- 외래키 참조 무결성 제약조건 활용 가능
- 저장공간의 효율화
- 단점
- 조회 시 조인을 많이 사용하여 성능이 저하된다.
- 조회 쿼리가 복잡하다.
- 데이터 저장 시 INSERT SQL이 2번 호출된다.
2. 단일 테이블 전략
통합 테이블로 변환하여 단일 테이블로 만드는 전략이다.
DTYPE으로 Album인지, Book인지, Movie인지 확인할 수 있어 DTYPE이 필수이다.
아래와 같이 구현할 수 있다.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
public class Item {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
위와 같이 JPA는 어노테이션 strategy만 바꾸면 전략이 바뀐도록 한다.
- 장점
- 조인이 필요 없으므로 일반적으로 조회 성능은 빠르다.
- 조회 쿼리가 단순하다.
- 단점
- 자식 엔티티가 매핑한 컬럼은 모두 null을 허용하게 된다.
- 단일 테이블에서 모든 것을 저장하기 때문에 테이블이 커진다. 따라서 조회 성능이 느려질 수도 있다.
3. 구현 클래스마다 테이블 전략
서브타입 테이블로 변환하여 구현 클래스마다 테이블을 따로 두는 전략이다. 중복 속성들을 각각의 Entity에 모두 넣는 것이다.
아래와 같이 구현할 수 있다.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
마찬가지로 @Ingeritance 어노테이션의 strategy를 바꾸고 부모를 추상 클래스로 설정하면 된다. 이때 @DiscriminatorColumn 어노테이션은 필요 없다.
- 장점
- 서브타입을 명확하게 구분하여 처리할 때 효과적이다.
- Not null 제약조건 사용이 가능하다.
- 단점
- 여러 자식 테이블을 함께 조회할 때 UNION SQL이 필요하기에 성능이 느리다.
- 자식 테이블을 통합하여 쿼리하기 어렵다.
하지만 이 전략은 DB 설계자와 ORM 전문가 둘 다 이 전략을 추천하지 않는다. 따라서 단순한 경우에는 단일 테이블 전략을, 비즈니스적으로 중요하고 복잡한 경우에는 조인 전략을 선택하면 좋다.
@MappedSuperclass
@MappedSuperclass는 공통 매핑 정보(속성)가 필요할 때 사용한다. 주로 id, name 값을 의미한다.
이는 상속관계 매핑과 관계가 없다. 엔티티도 아니다. 따라서 테이블과 매핑이 안된다. 속성을 상속받기만 하는 것이다. 부모 클래스를 상속 받는 자식 클래스에 매핑 정보(속성)만 제공한다. 조회나 검색은 불가능하며 직접 생성해서 사용할 일이 없으므로 추상 클래스를 권장한다.
아래와 같이 구현할 수 있다.
@MappedSuperclass
public abstract class BaseEntity {
private String createdBy;
private LocalDateTime localDateTime;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
}
@Entity
public class Member extends BaseEntity{
...
}
'Spring > SpringBoot&JPA' 카테고리의 다른 글
[JPA] 값 타입 (기본값, 임베디드 타입, 불변객체, 비교, 컬렉션) (0) | 2024.04.02 |
---|---|
[JPA] 프록시, 즉시/지연 로딩, 영속성 전이(CASCADE), 고아 객체 (0) | 2024.04.01 |
[JPA] 다양한 연관관계 (다대일, 일대다, 일대일, 다대다) (0) | 2024.03.29 |
[JPA] 연관관계 매핑 (단방향, 양방향, 연관관계의 주인) (0) | 2024.03.26 |
[JPA] 엔티티 매핑 (매핑 어노테이션, DDL, 기본키 전략) (0) | 2024.03.22 |