[JPA & Hibernate] Inheritance Hierarchies and Mappings

원알렉스·2020년 8월 20일
0

JPA

목록 보기
9/16
post-thumbnail

깃허브 소스코드
Udemy 강의영상

🚀 JPA Inheritance Hierarchies and Mappings

✔ SINGLE_TABLE

  • 부모 클래스
@Entity
@Getter
@Table(name = "employees")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "EMPLOYEE_TYPE")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    private String name;

    public Employee(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return String.format("Employee[%s]", this.name);
    }
}
  • 자식 클래스
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PartTimeEmployee extends Employee {

    private BigDecimal hourlyWage;

    @Builder
    public PartTimeEmployee(String name, BigDecimal hourlyWage) {
        super(name);
        this.hourlyWage = hourlyWage;
    }
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FullTimeEmployee extends Employee {

    private BigDecimal salary;

    @Builder
    public FullTimeEmployee(String name, BigDecimal salary) {
        super(name);
        this.salary = salary;
    }
}
  • @Inheritancestrategy의 기본값은 SINGLE_TABLE 입니다.
  • SINGLE_TABLE은 상속 관계에 있는 테이블들을 모두 합쳐서 하나의 테이블로 저장합니다. 즉, 부모 테이블만 생성됩니다.
  • 기본적으로 DTYPE 이라는 새로운 칼럼이 생성되고, 이 칼럼은 어떠한 자식 클래스인지 구분해줍니다. 해당 칼럼명은 @DiscriminatorColumn 어노테이션으로 재정의 할 수 있습니다.
  • 데이터를 조회할 때 쿼리는 매우 단순하므로 성능면에서는 좋으나, 테이블이 생성될 때 null 값이 생성되므로 데이터베이스 설계면에서는 비효율적입니다.

✔ TABLE_PER_CLASS

  • 부모 클래스
@Entity
@Getter
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {...}
  • 상속 관계에 있는 클래스에 대해 모두 개별적인 테이블을 생성해줍니다.
  • 데이터를 조회할 때, 즉 부모 클래스를 조회할 때 UNION을 사용하고 성능도 준수한 편입니다.
  • 그러나 자식 클래스가 부모 클래스의 모든 칼럼을 상속 받으므로 공통 칼럼에 대한 중복 현상이 발생합니다.

✔ JOINED

@Entity
@Getter
@Inheritance(strategy = InheritanceType.JOINED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {...}
  • 부모 클래스의 테이블은 자신의 칼럼만을 가지고, 자식 클래스의 테이블은 부모 클래스의 ID를 참조하는 외래키랑 자신의 칼럼만을 가집니다.
  • 그래서 데이터베이스의 설계면에서는 가장 효율이 좋습니다.
  • 부모 클래스를 조회할 경우, 각각의 자식 클래스에 대해 JOIN 연산을 수행하므로 성능면에서는 떨어집니다.

✔ Mapped Super Class

  • 부모 클래스
@Getter
@MappedSuperclass
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Employee {...}
  • @MappedSuperClass가 선언되어 있는 클래스는 엔티티가 아닙니다. 당연히 테이블과 매핑도 안됩니다.
  • 단순히 부모 클래스를 상속 받는 자식 클래스에 추가 정보만 제공해줍니다.
  • 이로 인해서 부모 클래스로 데이터를 조회할 수 없게 됩니다.
  • 직접 객체화해서 사용할 일이 없으므로 추상 클래스로 만들어 줍니다.
  • 주로 등록일, 수정일, 등록자, 수정자 같이 전체 엔티티에서 공통으로 적용하는 정보를 모을때 사용합니다.
  • 데이터베이스 안에서는 자식 클래스의 테이블만 생성되고 TABLE_PER_CLASS와 같은 형태로 생성됩니다.

Note
💨 JPA에서 @Entity 클래스는 @Entity@MappedSuperClass로 지정한 클래스만 상속 받을 수 있습니다.

🎯 How to choose?

데이터베이스 디자인과 무결성을 고려한다면 JOINED 방식을 추천합니다.

그러나 성능을 더 고려한다면 SINGLE_TABLE을 추천합니다.

반면에 TABLE_PER_CLASS하고 Mapped Super Class를 사용하게 된다면 각 테이블마다 중복되는 칼럼이 생성되므로 비추천합니다.

profile
Alex's Develog 🤔

0개의 댓글