고급 매핑

D A S H B O A R D
D E V E L O P
S E C U R I T Y
 상속관계 매핑
 @MappedSuperclass
주요내용
Reference

 상속관계 매핑

관계형 데이터베이스는 상속관계라는 것이 존재하지 않는다.
하지만 슈퍼타입-서브타입 관계라는 모델링 기법이 객체 상속과 유사하기 때문에 해당 모델링을 이용해 상속관계를 구현한다.
즉, 상속관계 매핑이란 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑

RDB 논리 모델 설계

RDB 물리 모델 설계

주요 어노테이션
@Inheritance(strategy = InheritanceType.XXX)
JOINED : 조인 전략
SINGLE_TABLE : 단일 테이블 전략
TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
@DiscriminatorColumn(name = “DTYPE”)
@DiscriminatorValue(”XXX)

슈퍼타입-서브타입 논리 모델을 실제 물리 모델로 구현하는 방법

DB 입장에서 구현할 수 있는 방식 3가지 존재
각각 테이블로 변환 → 조인 전략
통합 테이블로 변환 → 단일 테이블 전략
서브타입 테이블로 변환 → 구현 클래스마다 테이블 전략
객체 입장에서는?
객체 입장에서는 3가지중 어떠한 전략을 가지고 DB를 구현하든 같다.
즉, JPA에서는 어떠한 전략을 가지고 가더라도 매핑이 가능하다!!

1. 조인 전략

Item, Album, Movie, Book 테이블로 나누어 생성
Join을 이용해 테이블 구성
예를 들면, 앨범이라는 항목을 추가할 때 가격과 이름은 Item 테이블에 들어가고, 나머지는 Album 테이블로 Join을 통해 저장된다.
DTYPE에는 어떠한 항목(Album, Movie, Book)인지 나타냄

Item.class

@Entity @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn public abstract class Item { @Id @GeneratedValue private Long id; private String name; private int price; }
Java
복사
저장의 경우 각 테이블에 맞는 정보를 알맞게 넣어준다.
조회의 경우 inner join 방식을 이용해 값을 가지고 온다.
@DiscriminatorColumn 을 통해 DTYPE이라는 컬럼을 생성해준다.
없어도 모든 테이블을 join을 통해 쿼리해볼 수 있기 때문에 상관없지만, 무조건 넣어주자! 효율상 당연히 훨씬 좋음
@DiscriminatorColumn(name = “원하는 이름”) 을 통해 이름도 지정 가능
이 때 DTYPE에 들어가는 정보는 자식 엔티티의 이름이 Default로 설정되어 있다.
자식 엔티티가 저장되는 값을 변경시키고 싶다면 @DiscriminatorValue(”원하는 이름”) 으로 지정 가능
만약 @Inheritance 를 지정해주지 않는다면?
단일 테이블 전략으로 생성된다.

Album.class

@Entity @DiscriminatorValue("Album1") // 없다면 Entity의 이름이 default public class Album extends Item{ private String artist; }
Java
복사

Movie.class

@Entity @DiscriminatorValue("Movie1") // 없다면 Entity의 이름이 default public class Movie extends Item{ private String director; private String actor; }
Java
복사

Book.class

@Entity @DiscriminatorValue("Book1") // 없다면 Entity의 이름이 default public class Book extends Item{ private String author; private String isbn; }
Java
복사
장점 vs 단점
장점
테이블 정규화
외래 키 참조 무결성 제약조건 활용가능
저장공간 효율화
단점
조회시조인을많이사용,성능저하
조회 쿼리가 복잡함
데이터 저장시 INSERT SQL 2번 호출

2. 단일 테이블 전략

모든 항목을 하나의 Item 테이블에 집어 넣는다.
DTYPE에는 어떠한 항목(Album, Movie, Book)인지 나타냄

Item.class

@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn public abstract class Item { @Id @GeneratedValue private Long id; private String name; private int price; }
Java
복사
코드 작성은 모두 JOIN 전략과 같지만, @Inheritance 전략에서 Type을 SINGLE_TABLE로 변경해주기만 하면 된다.
@DiscriminatorColumn 을 통해 DTYPE이라는 컬럼을 생성해주는데, 단일 테이블 전략에서는 무조건!! 있어야함
SINGLE_TABLE 전략에서는 없어도 DTYPE을 자동으로 생성해준다.(JPA 표준상 있어야 하지만, 없는 경우 Hibernate가 알아서 생성해줌)
Item에 abstract가 있는 이유?
Item이 만약 단독으로 저장되는 겨우에는 abstract가 없다.
하지만 우리가 보는 예제들은 Item이 나머지 엔티티들과 상속관계이기 때문에 단독으로 저장되는 것이 아니기 때문에 abstract를 사용해준다.

Album.class

@Entity @DiscriminatorValue("Album1") // 없다면 Entity의 이름이 default public class Album extends Item{ private String artist; }
Java
복사

Movie.class

@Entity @DiscriminatorValue("Movie1") // 없다면 Entity의 이름이 default public class Movie extends Item{ private String director; private String actor; }
Java
복사

Book.class

@Entity @DiscriminatorValue("Book1") // 없다면 Entity의 이름이 default public class Book extends Item{ private String author; private String isbn; }
Java
복사
장점 vs 단점
장점
조인이 필요 없으므로 일반적으로 조회 성능이 빠름
조회 쿼리가 단순함
단점
자식 엔티티가 매핑한 컬럼은 모두 null 허용
단일테이블에모든것을저장하므로테이블이커질수있다.상황에 따라서 조회 성능이 오히려 느려질 수 있다.

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

Item 테이블을 만들지 않고, 각 항목들의 테이블이 Name과 Price 컬럼을 가지고 있도록 구현

Item.class

@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class Item { @Id @GeneratedValue private Long id; private String name; private int price; }
Java
복사
구현 클래스마다 테이블 전략을 구현할 경우에는 Item이라는 Table이 실제로 생성되지 않는다.
그렇기 때문에 Item 엔티티는 abstract 를 이용해 추상화 엔티티로써 사용한다.
@DiscriminatorColumn는 있어도 사용되지 않기 때문에 사용하지 않는다.

Album.class

@Entity public class Album extends Item{ private String artist; }
Java
복사

Movie.class

@Entity public class Movie extends Item{ private String director; private String actor; }
Java
복사

Book.class

@Entity public class Book extends Item{ private String author; private String isbn; }
Java
복사
장점 vs 단점 - 얘는 장점 단점을 떠나서 데이터베이스 설계자와 ORM 전문가 둘 다 추천X
장점
서브 타입을 명확하게 구분해서 처리할 때 효과적
not null 제약조건 사용 가능
단점
여러 자식 테이블을 함께 조회할 때 성능이 느림(UNION SQL 필요)
자식 테이블을 통합해서 쿼리하기 어려움

 @MappedSuperclass

공통 매핑 정보가 필요할 때 사용(id, name)
상속관계 매핑X ⇒ 얘가 매우 중요!!
엔티티X, 테이블과 매핑X
부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공
조회, 검색 불가(em.find(BaseEntity) 불가)
직접 생성해서 사용할 일이 없으므로 추상 클래스 권장
사용
테이블과 관계 없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모으는 역할
주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용
참고
@Entity 클래스는 엔티티나 @MappedSuperclass로 지정한 클래스만 상속 가능

객체

DB

BaseEntity.class

@MappedSuperclass public abstract class BaseEntity { private String createBy; private LocalDateTime createDate; private String lastModifiedBy; private LocalDateTime lastModifiedDate; }
Java
복사

Member.class

@Entity public class Member extends BaseEntity{ }
Java
복사
일반적으로 상속하는것과 같이 extends를 이용하여 사용
이렇게 되면은 BaseEntity를 상속받은 모든 엔티티들의 테이블에 BaseEntity의 정보가 들어가게 된다.