백엔드

[Spring Boot] JPA 고급매핑 상속관계 매핑, @MappedSuperclass

육빔 2024. 9. 1. 16:08
728x90
반응형

객체지향적 속성을 살릴려면 추상화, 상속, 다형성, 캡슐화 이러한 4가지를 살릴 수 있어야 한다. 여기서 상속관계를 데이터베이스로 어떻게 매핑할 수 있을까?

 

JPA에서는 3가지 전략을 제공하는데

 

  • 조인 전략 (Joined Strategy)
  • 단일 테이블 전략 (Single Table Strategy)
  • 구현 클래스마다 테이블 전략 (Table per Class Strategy)

로 나누어진다.

 

1. 조인 전략 (Joined Strategy)

조인 전략은 상속관계에 있는 각 클래스를 각각의 테이블에 매핑하고, 쿼리 시 이들 테이블을 조인하여 데이터를 조회하는 방법입니다.

  • 장점:
    • 정규화된 구조로, 데이터의 중복이 최소화됩니다.
    • 하위 클래스의 데이터를 추가하거나 변경할 때, 부모 클래스 테이블에는 영향을 주지 않습니다.
  • 단점:
    • 조인이 발생하므로 조회 성능이 떨어질 수 있습니다.
    • 설계가 복잡해질 수 있습니다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int price;
}

@Entity
public class Book extends Item {
    private String author;
    private String isbn;
}

@Entity
public class Movie extends Item {
    private String director;
    private String actor;
}

 

 

위처럼 DTYPE으로 설정하면 Item 컬럼에 DTYPE으로 Booke인지 Movie인지 구별할 수 있게 entity명이 들어가게 됩니다. 따라서 데이터를 삽입할때 Item, Book이나 Item, Movie로 조인을 하면서 진행함으로 조회, 삽입, 삭제 속도가 느릴수 있습니다.

 

2. 단일 테이블 전략 (Single Table Strategy)

이름 그대로 단일 테이블 전략은 모든 상속 구조를 하나의 테이블에 매핑하는 방법입니다. 이 전략은 부모 클래스와 자식 클래스를 모두 하나의 테이블에 저장하며, 자식 클래스의 데이터는 null로 처리됩니다. 또 조인을 전혀 사용하지 않아 가장 빠른 기법입니다.

  • 장점:
    • 조인이 발생하지 않아 조회 성능이 좋습니다.
    • 테이블 수가 적어서 단순한 구조를 가집니다.
  • 단점:
    • 자식 클래스의 모든 속성이 단일 테이블에 들어가므로, 테이블의 컬럼이 많아질 수 있습니다.
    • 많은 null 값이 존재할 수 있습니다. (자식 엔티티의 컬럼은 모두 null을 허용해야 됩니다.)

 

또 @DiscriminatorColumn annotation을 사용하지 않아도 DTYPE이 생성된다.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int price;
}

@Entity
public class Book extends Item {
    private String author;
    private String isbn;
}

@Entity
public class Movie extends Item {
    private String director;
    private String actor;
}

 

3. 구현 클래스마다 테이블 전략 (Table per Class Strategy)

이 전략은 각 자식 클래스마다 별도의 테이블을 생성하는 방법입니다. 부모 클래스는 테이블이 없고, 자식 클래스의 테이블이 각각 모든 속성을 가집니다.

  • 장점:
    • 객체의 타입에 따라 구분된 테이블에 저장되므로, 조회 시 성능이 좋을 수 있습니다.
  • 단점:
    • 각 자식 클래스마다 테이블이 생성되며, 데이터 중복이 발생할 수 있습니다.
    • 유지보수와 설계가 복잡해질 수 있습니다.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
    @Id @GeneratedValue
    private Long id;
    private String name;
    private int price;
}

@Entity
public class Book extends Item {
    private String author;
    private String isbn;
}

@Entity
public class Movie extends Item {
    private String director;
    private String actor;
}

 

또 변경된 부분은 Item class를 abstract로 만들어 추상화를 해줘야 됩니다. abstract가 없으면 Item을 사용하는 걸로 알고 table이 생성되고 각각의 table이 모든 정보를 저장하는 것입니다. 즉 부모타입으로 조회할 때 모든 자식테이블을 전부 탐색합니다. 그래서 TABLE_PER_CLASS 전략은 거의 사용하지 않습니다. 장점으론 서브 타입을 명확하게 구분해서 처리하는 것 말고는 조회할때 UNION SQL이 필요하고 다른 성능상 문제로 인해 사용하지 않습니다.

 

@MappedSuperclass는 JPA에서 제공하는 상속 매핑 중 하나로, 엔티티 클래스들 사이에서 공통적으로 사용되는 필드를 정의하는 데 사용됩니다. @MappedSuperclass를 사용하면 테이블을 생성하지 않고, 상속받는 엔티티 클래스들에 공통 속성들을 공유할 수 있습니다. 이러한 편리성으로 가장 많이 사용되는 듯 합니다.

주요 특징

  1. 테이블 생성되지 않음:
    • @MappedSuperclass로 지정된 클래스는 데이터베이스에 테이블로 매핑되지 않습니다.
    • 이 클래스는 단순히 속성과 매핑 정보를 상속받는 하위 엔티티 클래스에 제공하는 역할을 합니다.
  2. 직접 사용 불가:
    • @MappedSuperclass는 단독으로 엔티티가 될 수 없으며, 엔티티 클래스에서 상속받아 사용해야 합니다.
    • 따라서 @Entity나 @Table 어노테이션을 사용할 수 없습니다.
  3. 상속된 속성 공유:
    • 이 클래스에서 정의된 필드들은 상속받는 엔티티 클래스에 매핑되어 데이터베이스 테이블의 컬럼으로 사용됩니다.

 

@MappedSuperclass
public abstract class BaseEntity {

    @Id @GeneratedValue
    private Long id;

    private LocalDateTime createdDate;
    private LocalDateTime lastModifiedDate;

}
  1.  
@Entity
public class User extends BaseEntity {

    private String username;
    private String email;

}

@Entity
public class Product extends BaseEntity {

    private String name;
    private int price;

}

 

이런식으로 작성하게 되면 Member table에 원하는 2가지 Column이 추가된 것을 볼 수있습니다. Team도 마찬가지입니다.

 

728x90
반응형