[개요]
최근 프로젝트를 진행하면서 User 객체를 나누어 설계하자는 말에 DB 설계를 진행하였다.
JPA를 사용하면 Entity의 상속관계에 대해 매핑이 가능하다는 점은 알고 있었지만 평소 개발을 하면서 설계해서 사용할 상황이 안 됐던건지, 설계를 잘 못한 탓인지는 모르겠지만 Entity를 상속해서 DB 설계를 진행하지는 않았는데 이번에 처음 도입하면서 어려움이 몇몇 부분에서 드러나기 시작했다.
처음 해보는 방법이라 테스트 코드를 작성하면서 많이 틀리기도 했던 부분들을 정리하려고 한다.
[상속관계 매핑]
우선 상속 매핑에 대해 간단하게 짚고 넘어가면 사실 관계형 데이터베이스(RDBMS)에서는 객체 지향에서 사용하는 상속 개념이 존재하지 않는다. 이를 제일 유사하게나마 표현할 수 있는게 Super 타입과 Sub 타입이라고 할 수 있는데 이에 대한 모델링 방법 즉, 모델링 전략 3가지에 대해 소개하고자 한다.
1. 조인 전략
- Entity 각각을 테이블로 만들고 자식 테이블이 부모 테이블의 기본 키를 받아 기본 키 + 외래 키로 사용하는 전략
- 자식 테이블의 구분을 위해 DTYPE 이라는 컬럼에 타입을 지정하여 구분한다.
ex)
Super 타입 Entity - Item
@Entity
@Inheritance(strategy = InheritanceType.JOINED) // 부모 클래스에 지정함. -> 전략에 따라 수정)
@DiscriminatorColumn(name = "DTYPE") // DB에 저장될 구분 컬럼명 지정 (default = DTYPE)
public abstract class Item {
@Id
@GeneratedValue
private Long id;
// ...
}
Sub 타입 Entity - Movie
@Entity
@DiscriminatorValue("MOVIE") // DTYPE의 값을 지정
@PrimaryKeyJoinColumn(name = "movie_id") // PK 조인을 위한 키 지정
public class Movie extends Item{
private String director;
private String actor;
// ...
}
장점
- 테이블 정규화
- 외래키 참조 무결성 제약조건 활용
- 저장공간 효율적으로 사용
단점
- 조회시 많은 조인으로 성능 저하 우려 -> 복잡성
- INSERT 문 두번 실행
2. 단일 테이블 전략
- 하나의 테이블을 사용하여 구분 컬럼인 DTYPE으로 데이터를 활용하는 전략
ex)
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id
@GeneratedValue
private Long id;
// ...
}
@Entity
@DiscriminatorValue("MOVIE") // DTYPE의 값을 지정
public class Movie extends Item{
private String director;
private String actor;
// ...
}
장점
- 빠른 조회 성능 (Join 불필요, 단순한 조회 쿼리)
단점
- 테이블이 커질 가능성이 있어 조회 성능 저하 가능성 있음
- 컬럼에 NULL 허용
3. 구현 클래스마다 테이블을 생성하는 전략
- 자식 Entity 마다 테이블을 생성하는 전략
- 추천하지는 않는다고 함.
ex)
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
@Id
@GeneratedValue
private Long id;
// ...
}
@Entity
@DiscriminatorValue("MOVIE")
public class Movie extends Item{
private String director;
private String actor;
// ...
}
장점
- 서브 타입을 구분해서 처리할 때 효과적
- not null 제약조건 사용 가능
단점
- 여러 자식 테이블 함께 조회시 성능 문제 (UNION 사용)
- 자식 테이블 통합 쿼리 어려움