상속하는 방법?

반응형
반응형

오랜만에 JPA 포스팅

JPA는 데이터베이스를 객체지향으로 표현한 ORM이라고 알고 있다.
그렇다는 소리는 객체지향 처럼 상속을 제공한다는 뜻이 된다. 

일반적으로 상속은 extends를 사용하게 되어진다.

간단하게 코드를 작성해봤다.

@Entity
public abstract class School {
  @Id
  @GeneratedValue
  private Long id;
  private String name;

}
@Entity
public class HighSchool extends School {}

이렇게 작성하고 나서 SQL를 확인했다.

create table School (
       DTYPE varchar(31) not null,
        id int8 not null,
        name varchar(255),
        primary key (id)
    )

아무튼 이렇게 만들어진다는 건데 결국 하나의 테이블로 저장이 된다는 사실을 알게 되었다.
이상하다.

내가 알던 상속이 아니야 
이건 그냥 하나로 합친거잖아

사실 저건 JPA에서 제공하는 상속 방법중 하나다.
JPA가 제공하는 상속방식에는 
총 3가지 방법이 존재한다.

조인 방식

이 방식 같은 경우 일반적인 상속 방식 
그러니까 class extends class 이 형태를 그대로 유지하면서
데이터 베이스에 저장되는 방식이다.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class School {
  ...
}

이런식으로 작성이 되어지는데
@Inheritance라는 어노테이션을 이용해서 상속 전략을 사용하고 있다.
그러면 이것은 어떻게 테이블을 생성할까?

create table HighSchool (
       id int8 not null,
        primary key (id)
    )
    
create table School (
       id int8 not null,
        name varchar(255),
        primary key (id)
    )

확인 결과 pk를 제외한 나머지 값은 추가적으로 추가가되지 않는 것 같아보인다.
이번에는 데이터를 추가해서 확인해보자.

이게 FK로 연결되는것 같은데 확인이 필요하다.

alter table HighSchool 
   add constraint FKhsyb5gogovhst2wt6twpq33gi 
   foreign key (id) 
   references School

요런 느낌으로 왜래키를 지정하고 있다.
참고로 저 키값은 school의 id값이다.

어떻게 보면 이 방식이 가장 정규화가 잘된 방법이라 생각이 들고,
또, 중복된 데이터가 최소한으로 표현되기 때문에 객체지향적인 방법이라 생각이 든다.

이것을 출력하면 어떻게 가져올까?

    select
        highschool0_.id as id2_2_0_,
        highschool0_1_.name as name3_2_0_,
        highschool0_.teacher as teacher1_0_0_ 
    from
        HighSchool highschool0_ 
    inner join
        School highschool0_1_ 
            on highschool0_.id=highschool0_1_.id 
    where
        highschool0_.id=?

코드를 보면 inner join을 한번더 걸기 때문에 데이터를 가져오기 위해서는 반드시 상위 그룹을 타야 된다는 단점을 가지고 있다.
어쩌면 성능이 조금은 떨어질지도 모르겠다.

이방법에는 굳이 이것들이 어떤것을 표현하는지에 대해 몰라도 된다.
왜냐하면 어차피 각자 테이블로 관리되어지기 때문이다.

하지만 위에서 잠깐 언급했던 싱글 테이블 방식에는 반드시 필요한 녀석이다.

---

그전에 이것을 추가하는 방법에 대해 이야기를 해보자.
가장 최상위 엔티티에

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public abstract class School {

@DiscriminatorColumn를 붙여주면 끝난다. 이것을 Dtype이라 부른다. 데이터 타입

기본값은 엔티티명이다. 또, 엔티티명의 기본값은 클래스 명이다.
고로 데이터 타입의 기본값은 클래스 명이라 할 수 있다.

만약 이것을 변경하고 싶다면

@Entity
@DiscriminatorValue(value = "H")
public class HighSchool extends School {

이런식으로 추가하면 된다.

다시 돌아 와서

싱글 테이블 방식

위에서 싱글 테이블 방식은 디폴트라고 했고
조금 전에는 @DiscriminatorColumn값이 반드시 필요하다고 하였다.
그러면 이것을 사용하지 않으면 어떻게 될까?

자동으로 등록이 되어지는 것을 확인했다.
이 방식은 하나의 테이블로 관리되어지기 때문에

   select
        highschool0_.id as id2_0_0_,
        highschool0_.name as name3_0_0_,
        highschool0_.teacher as teacher4_0_0_ 
    from
        School highschool0_ 
    where
        highschool0_.id=? 
        and highschool0_.DTYPE='H'

하나의 select로 조회가 가능하다는 사실이다.
어쩌면 select할때는 조인 방식보다 조금더 성능 측면에서는 우세한 것 같다.

하지만 데이터가 들어가지 않는 곳은 null로 기입이 되어지는 현상이 존재한다.

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

이 방식은 사용하지 않는게 좋다고 했다. 왜냐하면 개발자라던지 DBA둘다 선호하지 않는 방법이라 한다.
장점은 서브 타입을 구분짓기 위해 효과적이지만, 자식 테이블을 통합해서 쿼리를 짜는 것이 어렵다고 한다.

결국은 보기 좋은 JOIN이냐 아니면 출력하기 좋은 싱글 테이블 인데
선택은 각자의 몫으로 

상속 방식과는 별계로 
상속 비스므리한 방식이다.

@MappedSuperclass
public class BaseEntity {
  private String timeUser;
  private String timeEnd;

  public void setTimeEnd(String timeEnd) {
    this.timeEnd = timeEnd;
  }

  public void setTimeUser(String timeUser) {
    this.timeUser = timeUser;
  }
}

요런식으로 각 필요한 데이터들을 한곳에 모아 넣고 이것을 상속을 하게 되면 이것을 사용할 수 있게 한다.

오해 할까봐 이야기 하는데 절대로 상속 방법과는 전혀 무관하다.

반응형

'JPA' 카테고리의 다른 글

JPQL 기본 문법  (0) 2021.12.18
값 타입 작성 방법  (0) 2021.12.12
Proxy?  (0) 2021.12.04
연관관계의 주인을 바꾸면 무슨일이 발생할까?  (0) 2021.10.30
Entity와 Table  (0) 2021.10.16

댓글

Designed by JB FACTORY