JPA 상속 관계에서 부모 클래스에 @DiscriminatorColumn을 명시하지 않으면 디폴트 구분자로 사용되는 컬럼명은?
JPA 상속 관계에서 하위 클래스에 @DiscriminatorValue로 명시하지 않으면 디폴트 값으로 사용되는 것은?
@MappedSuperclass는 언제 사용하면 좋은가?
상속관계 맵핑 방법
객체는 상속이 있지만 관계형 데이터베이스는 상속 관계가 없음
슈퍼타입 - 서브타입 관계라는 모델링 기법이 객체 상속과 유사
실제 구현 방법 3가지
조인 전략: 부모, 자식을 각 테이블로 변환 후 조인
단일 테이블 전략: 자식들을 부모에 합쳐 한 테이블로 변환
클래스마다 각 테이블 전략: 부모를 각 자식들에 합쳐 여러 테이블로 변환
주요 어노테이션
@Inheritance(strategy = InheritanceType.XXX)
JOINED: 조인 전략
SINGLE_TABLE: 단일 테이블 전략
TABLE_PER_CLASS: 클래스마다 각 테이블 전략
@DistriminatorColumn(name = "DTYPE")
@DiscriminatorValue("XXX)
조인 전략
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item{
@Id @GeneratedValue
private Long id;
...
}
@Entity
@DiscriminatorValue("Album")
public class Album extends Item {
private String artist
}
효율적으로 잘 사용해야할 때 사용하는 방식
@DiscriminatorColumn을 명시하지 않으면 자동으로 DTYPE이라는 컬럼이 구분자로 사용되며, 해당 값으로 해당 ITEM_ID가 어느 하위 테이블과 연관이 있는지 파악을 할 수 있음.
@DiscriminatorColumn을 명시하면 DTYPE 대신 해당 컬럼 네임으로 구분자를 사용 가능
DTYPE 구분자의 Value로 들어갈 하위 테이블의 이름은 @DiscriminatorValue로 명시할 수 있으며 명시하지 않으면 기본적으로 해당 테이블의 이름이 들어감
insert시 Item, Album 모두에 값이 들어가게 되며 find시 join을 통해 가져옴
장점
테이블 정규화
외래 키 참조 무결성 제약조건 활용 가능
저장공간 효율화
단점
조회시 조인을 많이 사용해 성능이 저하될 수 있음
조회 쿼리의 복잡성
데이터 저장시 INSERT SQL 2번 호출
단일 테이블 전략
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
public abstract class Item{
@Id @GeneratedValue
private Long id;
...
}
조인 전략에 비해 간단할 경우에 사용하며, 기본적으로 단일 테이블 전략을 사용하다가 정교한 컨트롤이 필요할 때 조인 전략으로 넘어가도 됨
단일 테이블 전략에서는 @DiscriminatorColumn 구분자가 필수인데, 코드상으로는 명시하지 않아도 자동 DTYPE으로 생성 됨.
장점
조인이 필요 없으므로 일반적으로 조회 성능이 빠름
조회 쿼리가 단순
단점
자식 엔티티가 맵핑한 컬럼은 모두 null을 허용해야 함
단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있고, 따라서 상황에 따라 조회 성능이 오히려 느려질 수 있음
클래스마다 각 테이블 전략
DB 설계자, ORM 전문가 모두 추천하지 않는 방식으로 사용하면 안됨
장점
서브 타입을 명확하게 구분해서 처리할 때 효과적
not null 제약조건을 사용할 수 있음
단점
여러 자식 테이블을 함께 조회할 때 성능이 느림(UNION SQL 필요) 자식 테이블을 통합해서 쿼리하기 어려움
@MappedSuperclass
@MappedSuperclass
public abstract class BaseEntity {
private String createBy;
private LocalDateTime createdDate;
private String lastModifiedBy;
private LocalDateTime lastModifiedDate;
...
}
@Entity
public class Team extend BaseEntity{
...
실제 상속의 개념은 아니고 속성만 상속하는 개념
예를 들어, 모든 테이블에 create_dt, create_user, update_dt, update_user가 있어야 하는 경우 BaseEntity에 해당 값 추가해주고 이 속성이 필요한 다른 테이블에서 해당 테이블을 extend
BaseEntity는 직접 사용할 일이 없으므로 abstract으로 선언하는게 좋음
참고로 @Entity 클래스는 @Entity나 @MappedSuperclass로 지정한 클래스만 상속 가능함