상속관계 매핑
•
관계형 데이터베이스는 상속관계라는 것이 존재하지 않는다.
•
하지만 슈퍼타입-서브타입 관계라는 모델링 기법이 객체 상속과 유사하기 때문에 해당 모델링을 이용해 상속관계를 구현한다.
•
즉, 상속관계 매핑이란 객체의 상속과 구조와 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의 정보가 들어가게 된다.