Be ready to study forever - 개발자 꿈나무
[JPA] 고급 매핑 - 3 본문
객체지향의 상속을 관계형 DB에서는 어떻게 표현할 수 있을까?
관계형 DB에서는 그나마 상속과 비슷하게 구현하는 방법은 슈퍼타입과 서브타입 모델링을 사용하여 구현할 수 있다.
그림과 같이 서브타입 테이블에 기본키에 외래키를 걸어버리면 1:1관계가 성립하면서 조인을 해서 두 테이블을 상속관계처럼 사용할 수 있다. 그렇지만, 다른 전략으로도 객체의 상속관계를 관계형DB에 표현할 수 있는데, 3가지 전략이 있다
- 조인전략(JOINED)
- 단일 테이블 전략(SIGNLE_TABLE)
- 구현 클래스마다 테이블 생성 전략(TABLE_PER_CLASS)
상속 매핑하는 방법)
이것 역시 어노테이션을 활용한다. 총 3가지 어노테이션이 있는데:
@Inheritance(strategy=InheritanceType.XXX)의 stategy를 설정해주면 된다. 부모 클래스에 선언한다. default 전략은 SINGLE_TABLE(단일 테이블 전략)이다.
- InheritanceType 종류
JOINED - @Inheritance(strategy=InheritanceType. JOINED)
SINGLE_TABLE - @Inheritance(strategy=InheritanceType. SINGLE_TABLE)
TABLE_PER_CLASS - @Inheritance(strategy=InheritanceType. TABLE_PER_CLASS)
@DiscriminatorColumn(name="DTYPE")
부모 클래스에 선언한다. 하위 클래스를 구분하는 용도의 컬럼이다. 관례는 default = DTYPE 그리고 자식 클래스의 @DiscriminatorValue("XXX")어노테이션에 xxx가 정의되어 있지 않다면 테이블 이름이 값으로 들어오게 된다.
@DiscriminatorValue("XXX")
하위 클래스에 선언한다. 엔티티를 저장할 때 슈퍼타입의 구분 컬럼에 저장할 값을 지정한다.
어노테이션을 선언하지 않을 경우 기본값으로 클래스 이름이 들어간다.
코드를 보면서 이해해보자면
ITEM(부모클래스)
@Entity
@Inheritance(strategy = InheritanceType.XXX) // 상속 구현 전략 선택
@DiscriminatorColumn(name="DTYPE") //자식클래스를 구별할 칼럼이름
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
}
ALBUM(자식클래스)
@Entity
@DiscriminatorValue("XXX") //부모 클래스의 DTYPE에 들어갈 이름 적지 않을 경우 자식테이블의 이름이 들어감
public class Album extends Item {
private String artist;
}
MOVIE(자식클래스)
@Entity
@DiscriminatorValue("XXX") //부모 클래스의 DTYPE에 들어갈 이름 적지 않을 경우 자식테이블의 이름이 들어감
public class Movie extends Item {
private String director;
private String actor;
}
BOOK(자식클래스)
@Entity
@DiscriminatorValue("XXX") //부모 클래스의 DTYPE에 들어갈 이름 적지 않을 경우 자식테이블의 이름이 들어감
public class Book extends Item {
private String author;
private String isbn;
}
상속 매핑 전략)
조인전략(JOINED)
그림과 같이 슈퍼타입과 서브타입의 테이블을 생성하는데
장점:
- 테이블의 정규화가 가능하다
- 외래 키 참조의 무결성을 지킬 수 있다
- 정규화 되어 중복되지 않음으로 저장공간의 효율화가 가능하다
단점:
- 조회시 조인을 사용해야 한다
- 데이터 저장시 INSERT쿼리가 두번 발생된다
단일 테이블 전략(SIGNLE_TABLE)
그림과 같이 상속을 그냥 한 테이블에 때려 박아서 구현하는 방법으로 간단하다.
장점:
- 조인이 필요 없으므로 조회가 빠르다
- 쿼리가 단순하다
단점:
- 자식 엔티티의 값에 NULL을 허용해야 한다. (치명적일 수도…)
- 테이블이 너무 커지게 될 경우 상황에 따라서 성능이 안 좋을 수가 있다.
구현 클래스마다 테이블 생성 전략(TABLE_PER_CLASS)
장점:
- 서브타입을 명확하게 구분할 때 효과적이다
- NULL값을 허용하지 않아도 된다.
단점:
- 여러 자식을 함께 조회할 때 성능이 매우 느리다.
- 자식테이블을 통합해서 쿼리하기가 힘들다
**김영한님의 말에 따르면, 구현 클래스마다 테이블 전략은 사용하지 않는 것이 좋다고 한다. 이유는, 자식테이블을 통합해서 무언가를 결과를 내야 할 경우 JOIN과 UNION이 필요함으로 성능이 매우 구려진다고… 그리고 간단한 테이블의 경우에는 단일테이블 전략을, 일반적인 경우라면 조인전략을 사용하는 것이 좋다고 하셨다
상속관계가 아닌 단순히 반복되는 값을 재활용 하고 싶다면? - @MappedSuperclass
때로는 createdAt, updatedAt, updatedBy같이 거의 모든 테이블에 들어가는 칼럼인 반복되는 필드를 적는건 매우 고통스럽다. 그럴경우엔 @MappedSuperclass를 사용해보자!
@MappedSuperClass란?
테이블과 관계가 없고 단지 엔티티에서 공통으로 사용하는 정보를 모아 중복되는 코드를 제거하고 싶은때 사용한다. 주로 등록일, 수정일 과 같이 엔티티에서 공통으로 사용하는 필드를 모아서 적용하면 중복도 제거되고 생산성도 높아진다!
**@Entity클래스는 같은@Entity클래스(DB에서 상속으로 처리)나 @MappedSuperclass(DB에서 칼럼으로만 처리)만 상속받을 수 있다.
그림에서 보듯이 중복되는 코드를 한 클래스에 모아서 @MappedSuperclass로 묶어주면 손쉽게 중복되는 코드 제거 완료! 하지만 DB에서는 상속으로 적용되지 않는다.
'Programming > JPA' 카테고리의 다른 글
[JPA] 값 타입 (0) | 2021.01.24 |
---|---|
[JPA] 엔티티매핑 (0) | 2021.01.24 |
[JPA] 다양한 연관관계 매핑-2 (0) | 2021.01.23 |
[JPA] 연관관계 매핑 기초 - 1 (0) | 2021.01.23 |
[JPA] 영속성 컨텍스트란? (0) | 2021.01.23 |