Spring JPA [상속관계 맵핑]

2021. 6. 17. 22:20Spring/JPA

상속관계 매핑

  • 관계형 데이터베이스는 상속 관계 X
  • 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사
  • 상속관계 매핑 : 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑

슈퍼타입 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법

  • 각각 테이블로 변환 ➔ 조인 전략
  • 통합 테이블로 변환 ➔ 단일 테이블 전략
  • 서브타입 테이블로 변환 ➔ 구현 클래스마다 테이블 전략

주요 어노테이션

  • @Inheritance(strategy = InheritanceType.XXX)
    • JOINED : 조인 전략
      • @Entity
        @Inheritance(strategy = InheritanceType.JOINED)
        @DiscriminatorColumn
        public class Item {
            @Id @GeneratedValue
            private Long id;
        
            private String name;
            private int price;
        
            public Long getId() {
                return id;
            }
        
            public void setId(Long id) {
                this.id = id;
            }
        
            public String getName() {
                return name;
            }
        
            public void setName(String name) {
                this.name = name;
            }
        
            public int getPrice() {
                return price;
            }
        
            public void setPrice(int price) {
                this.price = price;
            }
        }    
      • SQL문
        create table Movie (
               actor varchar(255),
                director varchar(255),
                id bigint not null,
                primary key (id)
            )
      • create table Item ( DTYPE varchar(31) not null, id bigint not null, name varchar(255), price integer not null, primary key (id) )
  ```sql
  Hibernate: 
      select
          movie0_.id as id1_2_0_,
          movie0_1_.name as name2_2_0_,
          movie0_1_.price as price3_2_0_,
          movie0_.actor as actor1_6_0_,
          movie0_.director as director2_6_0_ 
      from
          Movie movie0_ 
      inner join
          Item movie0_1_ 
              on movie0_.id=movie0_1_.id 
      where
          movie0_.id=?
  ```

  [![2021-06-17-8-22-44.png](https://i.postimg.cc/Vv6G4f7H/2021-06-17-8-22-44.png)](https://postimg.cc/PpgQ5jnm)
  • SINGLE_TABLE : 단일 테이블 전략
    • @Entity
      @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
      @DiscriminatorColumn
      public class Item {
          @Id @GeneratedValue
          private Long id;
      
          private String name;
          private int price;
      
          public Long getId() {
              return id;
          }
      
          public void setId(Long id) {
              this.id = id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getPrice() {
              return price;
          }
      
          public void setPrice(int price) {
              this.price = price;
          }
      }
    • SQL문
    • create table Item ( DTYPE varchar(31) not null, id bigint not null, name varchar(255), price integer not null, artist varchar(255), author varchar(255), isbn varchar(255), actor varchar(255), director varchar(255), primary key (id) )
    • 2021-06-17-8-32-40.png
  • TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
    •  
  • @DiscriminatorColumn(name = "DTYPE")
    • 부모 클래스에 구분 컬럼이다. 이 컬럼으로 저장된 자식 테이블을 구분 할 수 있다. 기본값은 DTYPE이다.
    • 2021-06-17-8-26-34.png
  • @DiscriminatorValue("XXX")
    • @Entity
      @DiscriminatorValue("movieTable")
      public class Movie extends Item{
          private String actor;
          private String director;
      
          public String getActor() {
              return actor;
          }
      
          public void setActor(String actor) {
              this.actor = actor;
          }
      
          public String getDirector() {
              return director;
          }
      
          public void setDirector(String director) {
              this.director = director;
          }
      }
      2021-06-17-8-28-43.png

조인전략

  • 장점
    1. 테이블 정규화
    2. 외래 키 참조 무결성 제약조건 활용가능
    3. 저장공간 효율화
  • 단점
    • 조회시 조인을 많이 사용, 성능 저하 ➔ 오히려 저장공간을 효율화 하기 때문에 생각보다는 성능이 저하 되지는 않는다.
    • 조회 쿼리가 복잡함
    • 데이터 저장시 INSERT SQL 2번 호출

단일 테이블 전략

  • 장점
    1. 조인이 필요없으므로 일반적으로 조회 성능이 빠르다.
    2. 조회 쿼리가 단순하다.
  • 단점
    • 자식 엔티티가 매핑한 컬럼은 모두 null 허용 (치명적)
    • 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다. 상황에 따라서 조회 성능이 오히려 느려질 수 있다.

구현 클래스마다 테이블 전략

2021-06-17-8-37-05.png

  • 이 전략은 데이터베이스 설계자 ORM 전문가 둘 다 추천 x
  • 장점
    • 서브 타입을 명확하게 구분해서 처리할 때 효과적
    • not null 제약조건 사용 가능
  • 단점
    • 여러 자식 테이블을 함께 조회할 때 성능이 느림(UNION SQL 필요)
    • select item0_.id as id1_2_0_, item0_.name as name2_2_0_, item0_.price as price3_2_0_, item0_.artist as artist1_0_0_, item0_.author as author1_1_0_, item0_.isbn as isbn2_1_0_, item0_.actor as actor1_6_0_, item0_.director as director2_6_0_, item0_.clazz_ as clazz_0_ from ( select id, name, price, artist, null as author, null as isbn, null as actor, null as director, 1 as clazz_ from Album union all select id, name, price, null as artist, author, isbn, null as actor, null as director, 2 as clazz_ from Book union all select id, name, price, null as artist, null as author, null as isbn, actor, director, 3 as clazz_ from Movie ) item0_ where item0_.id=?
  • 자식 테이블을 통합해서 쿼리하기 어렵다.

@MappedSuperclass

  • 공통 매핑 정보가 필요할 때 사용(id, name)

2021-06-17-9-38-29.png

  • 상속관계 매핑 X
  • 엔티티 X, 테이블과 매핑 X
  • 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공
  • 조회, 검색 불가(em.find(BaseEntity) 불가)
  • 직접 생성해서 사용할 일이 없으므로 추상 클래스 권장
@MappedSuperclasspublic abstract class BaseEntity {    private String createBy;    private LocalDateTime createAt;    private String modifiedBy;    private LocalDateTime modifiedAt;    public String getCreateBy() {        return createBy;    }    public void setCreateBy(String createBy) {        this.createBy = createBy;    }    public LocalDateTime getCreateAt() {        return createAt;    }    public void setCreateAt(LocalDateTime createAt) {        this.createAt = createAt;    }    public String getModifiedBy() {        return modifiedBy;    }    public void setModifiedBy(String modifiedBy) {        this.modifiedBy = modifiedBy;    }    public LocalDateTime getModifiedAt() {        return modifiedAt;    }    public void setModifiedAt(LocalDateTime modifiedAt) {        this.modifiedAt = modifiedAt;    }}
public class Item extends BaseEntity

Main

Movie movie = new Movie();            movie.setActor("장현준");            movie.setDirector("LeeJiHong");            movie.setName("취업하자");            movie.setPrice(10000);            movie.setCreateBy("jang");            movie.setCreateAt(LocalDateTime.now());            em.persist(movie);

결과

2021-06-17-9-41-42.png

@MappedSuperclass 정리

  • 테이블과 관계 없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모으는 역할
  • 주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용
  • 참고: @Entity 클래스는 엔티티나 @MappedSuperclass로 지정한 클래스만 상속 가능

참고자료

'Spring > JPA' 카테고리의 다른 글

JPQL은 만능이 아니다!  (0) 2021.12.23
[Spring JPA] 즉시로딩과 지연로딩  (0) 2021.06.28
[Spring JPA] 다양한 연관관계 매핑  (0) 2021.04.19
Spring JPA 영속성 컨텍스트  (0) 2021.02.28
Spring JPA 엔티티 맵핑  (0) 2021.02.27