상속관계 매핑
관계형 데이터 베이스는 상속 관계를 구현 할 수 없다는 단점을 가지고 있다.
그나마 슈퍼타입, 서브타입 관계가 객체 상속과 유사하다.
슈퍼타입, 서브타입 논리모델을 실제 물리 모델로 구현하는 방법
- 각각 테이블로 변환 : 조인 전략(Joined)
- 통합 테이블로 변환 : 단일 테이블 전략
- 서브타입 테이블로 변환 : 구현 클래스마다 테이블 전략
매핑 시 주로 사용하는 어노테이션
1. @Inheritance(strategy=InheritanceType.XXXX)
- JOINED : 조인 전략
- SINGLE_TABLE : 단일 테이블 전략
- TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
2. @DiscriminatorColumn(name="DTYPE") → default가 DTYPE
3. @DiscriminatorValue("XXX")
단일 테이블 전략(기본값)
- 단일 테이블은 Inheritance의 기본값이기 때문에 명시하지 않아도 사용 가능하다.
- 단일 테이블은 DTYPE이 자동으로 무조건 들어간다. (DiscriminatorColumn이 없어도) : 그게 없으면 단일테이블은 구분하기 너무 힘들기 때문에 자동으로 들어간다.
장점
: 조인이 필요없어 일반적으로 조회성능이 빠름, 조회쿼리가 단순하다.
단점
: 자식 엔티티가 매핑한 컬럼은 모두 null 허용(무결성 문제),
: 단일 테이블에 모든 것을 저장하므로 테이블이 커질수 있다.
: 상황에 따라 조회 성능이 오히려 느릴 수 있다.
아래는 사용 예시 이다.
/* Item.java */
@Entity
// 기본이 싱글 테이블(굳이 안적어도됨)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Item {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
/* Movie.java */
@Entity
public class Movie extends Item{
private String director;
private String actor;
}
// ... 외 Book, Album 존재 추후 작성
위에 처럼 작성 후 실행 시키면 아래 이미지 처럼 하나의 테이블에 모든 컬럼이 생성된다.
조인전략(JOINED)
- 조인전략은 조회 할 때도 조인해서 가져옴
장점
: 테이블 정규화, 외래키 참조 무결성 제약조건 활용가능, 저장공간 효율성
단점
: 조회 시 조인을 많이 사용, 성능저하( 잘 조인하면 괜찮긴함 )
: 조회 쿼리가 복잡하다.
: 데이터 저장 시 insert 2번 호출( 부모와 자식 둘다 데이터를 넣어줘야하기 때문 )
/* Item.java */
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Item {
@Id @GeneratedValue
private Long id;
private String name;
private int price;
}
/* Movie.java */
@Entity
public class Movie extends Item{
private String director;
private String actor;
}
// ... 외 Book, Album 존재 추후 작성
Movie movie = new Movie();
movie.setDirector("봉준호");
movie.setActor("송강호");
movie.setName("기생충");
movie.setPrice(12000);
em.persist(movie);
조인 전략 사용 후 Movie 값을 등록 하면 아래 이미지 처럼 결과가 등록됨
만약 조인 전략 사용 시 *DTYPE을 지정하고 싶다면?? DiscriminatorColumn 사용!
* 여기서 DTYPE 이란 어떤 테이블을 조회한건지 구분해주는 구분 컬럼을 말한다!
DiscriminatorColumn은 컬럼 이름이 기본값으로 'DTYPE' 이 들어가고 이름을 지정하고 싶을때는
DiscriminatorColumn( name = "test" ) 이런 식으로 사용한다.
DTYPE이 없으면 어떤 타입으로 데이터가 삽입된건지 알기 어렵기 때문에 웬만하면 사용하는걸 권장!
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // 기본이 싱글 테이블
@DiscriminatorColumn // 기본 컬럼명이 DTYPE
public abstract class Item {
...
}
만약 DTYPE 의 value 값을 클래스 이름이 아닌 내가 지정해 주고 싶다면?? DiscriminatorValue 사용!
@Entity
@DiscriminatorValue("M") // DTYPE의 value 값을 다른걸로 사용하고싶을때
public class Movie extends Item{
...
}
구현 클래스마다 테이블 전략(TABLE_PER_CLASS)
- 단순하게 값을 넣었다 뺄때는 편하다.
- 구현 클래스의 문제점 → 쓰면 안되는 전략 : 데이터를 삽입할때는 좋다. 하지만 조회할때 부모 클래스인 Item으로 Movie 데이터를 조회하려면 union으로 모든 테이블을 합치기 때문에 성능이 떨어진다.( 비효율적 )
- 이 전략은 데이터베이스 설계자와 ORM 전문가 둘다 비 추천
장점
: 서브 타입을 명확하게 구분해서 처리 할 때 효과적, not null 조건 사용가능
단점
: 여러 자식 테이블을 함께 조회 할 때 성능이 느림(union sql), 자식 테이블을 통합해서 쿼리하기 어려움
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn
public abstract class Item {
...
}
'JAVA' 카테고리의 다른 글
[JAVA] 프록시 (0) | 2022.01.04 |
---|---|
[JAVA] @MappedSuperclass (0) | 2022.01.04 |
[JAVA] JPA 다양한 연관관계 매핑 (0) | 2021.12.09 |
[JAVA] JPA 연관관계 매핑( 양방향 ) (0) | 2021.11.17 |
[JAVA] JPA 연관관계 매핑( 단방향 ) (0) | 2021.11.16 |