고급 매핑
JPA에서 다음과 같은 복잡한 관계를 매핑하기 위한 여러 방법들이 존재한다.
● 객체의 상속 관계를 데이터베이스에 맞춰 매핑
● 공통으로 중복되는 값들을 매핑
1. 상속 관계 매핑
관계형 데이터베이스에는 객체지향 언어에서 다루는 상속이라는 개념이 없다.
대신 슈퍼타입 서브타입 관계(Super-Type Sub-Type Relationship)라는 모델링 기법이 객체의 상속 개념과 가장 유사하다.
[슈퍼 타입 서브타입 논리 모델]
오른쪽의 객체 간 상속관계와 유사한 슈퍼 타입 서브타입 관계 모델링은 왼쪽과 같이 구성되어있다.
슈퍼 타입 서브타입 논리 모델을 실제 물리 모델인 테이블로 구현할 때는 3가지 방법을 선택할 수 있다.
■ 조인 전략
조인 전략은 엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본키를 받아서 기본 키 + 외래 키로 사용하는 전략이다.
[조인 전략 테이블 구조]
[조인 전략 매핑]
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
}
...
● @Inheritance(strategy = InheritanceType.JOIND)
◎ 상속 매핑은 부모 클래스에 @Inheritance를 사용해야 한다.
◎ 전략에 맞게 strategy를 설정하면 된다(조인 전략이기 때문에 JOIND 사용).
● @DiscriminatorColumn(name = "DTYPE")
◎ 테이블에는 타입을 표기할 수 없기 때문에 구분 컬럼을 지정해주어야 한다.
◎ 부모 클래스에 구분 컬럼을 지정한다.
◎ 기본값은 DTYPE이다.
● @DiscriminatorValue("A")
◎ 엔티티를 저장할 때 구분 컬럼에 입력할 값을 지정한다.
ex) Album을 저장하면 구분 컬럼인 DTYPE에 A가 저장된다.
□ 조인 전략의 장단점
● 장점
◎ 테이블이 정규화된다.
◎ 외래 키 참조 무결성 제약조건을 활용할 수 있다.
◎ 저장공간을 효율적으로 사용한다.
● 단점
◎ 조회할 때 조인이 많이 사용되므로 성능이 저하될 수 있다.
◎ 조회 쿼리가 복잡하다.
◎ 데이터를 등록할 INSERT SQL을 두 번 실행한다.
■ 단일 테이블 전략
단일 테이블 전략은 이름 그대로 테이블을 하나만 사용한다.
하나의 테이블에 모든 상속 정보를 저장하고 구분 컬럼(DTYPE)으로 어떤 자식 데이터가 저장되었는지 구분한다.
[단일 테이블 전략]
[단일 테이블 전략 매핑]
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id @GeneratedValue
@Column(name = "ITEM_ID")
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
private String artist;
}
...
@Inheritance의 strategy만 전략에 따라 다르고, 나머지는 앞의 조인 전략과 전부 동일하다.
테이블 하나에 모든 것을 통합하므로 구분 컬럼을 필수로 사용해야 한다.
□ 단일 테이블 장단점
● 장점
◎ 조인이 필요 없으므로 일반적인 조회 성능이 빠르다.
◎ 조회 쿼리가 단순하다.
● 단점
◎ 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다.
ex) Album을 저장하면 테이블에 Album과 관련된 ARTIST와 Item의 id, name, price를 제외하고 모두 null로 저장된다.
◎ 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다.
◎ 상황에 따라서는 조회 성능이 오히려 느려질 수 있다.
■ 구현 클래스마다 테이블 전략
이 전략은 자식 엔티티마다 테이블을 만드는 전략이다.
자식 테이블 각각에는 필요한 컬럼이 모두 있다.
[구현 클래스마다 테이블 전략]
이 전략은 여러 자식 테이블을 함께 조회할 때 성능이 느리다(SQL에 UNION을 사용해야 한다).
비슷한 이유로 자식 테이블을 통합해서 쿼리하기 어렵다.
이처럼 테이블에서 상속을 매핑하기 위해 발생하는 단점이 명확하기 때문에 일반적으로 권장되지 않는다.
2. @MappedSuperclass
부모 클래스는 테이블과 매핑하지 않고 부모 클래스를 상속받는 자식 클래스에게 매핑 정보만 제공하고 싶으면 @MappedSuperclass를 사용하면 된다.
[공통 매핑 정보가 필요한 테이블]
Member와 Seller는 서로 관계가 없는 테이블과 엔티티이다.
@MappedSuperclass를 사용하면, 테이블은 그대로 두고 객체 모델의 id, name 두 공통 속성을 부모 클래스로 모으고 객체 상속 관계로 만들 수 있다.
[@MappedSuperclass 매핑]
@MappedSuperclass
public abstract class BaseEntity {
@Id @GeneratedValue
private Long id;
private String name;
}
@Entity
public class Member extends BaseEntity {
private String email;
}
@Entity
public class Member extends BaseEntity {
private String shopName;
}
@MappedSuperclass를 공통 정보를 제공할 부모 클래스에 사용하면 된다.
자식 클래스는 그냥 부모 클래스를 상속 받기만 하면 된다.
※ @MappedSuperclass는 엔티티가 아니므로 엔티티 매니저나 JPQL등에서 사용할 수 없다.
@MappedSuperclass로 지정한 클래스는 직접 생성해서 사용할 일이 거의 없으므로 추상 클래스로 만드는 것이 권장된다.
'Spring > JPA' 카테고리의 다른 글
#9 값 타입 (0) | 2021.08.30 |
---|---|
#8 프록시와 연관관계 관리 (0) | 2021.08.29 |
#6 다양한 연관관계 매핑 (0) | 2021.08.28 |
#5 연관관계 매핑 기본 (0) | 2021.08.27 |
#4 엔티티 매핑 (0) | 2021.08.27 |
댓글