고급 매핑

김민우·2022년 9월 3일
0

JPA

목록 보기
6/10

RDB는 상속관계가 없다. 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사하지만 상속이라 볼 수는 없다. 객체의 상속을 슈퍼타입 서브타입 관계로 매핑해주는 무언가가 있어야한다.

상속 관계 매핑을 통해서 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑할 수 있다.

논리 모델 vs 물리 모델

  • 왼쪽이 논리 모델, 오른쪽이 물리 모델이다.

슈퍼타입 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법은 3가지가 있다.

  1. 각각 테이블로 변환 -> 조인전략
  2. 통합 테이블로 변환 -> 단일 테이블 전략
  3. 서브타입 테이블로 변환 -> 구현 클래스마다 테이블 전략

하나씩 알아보자.


상속관계 매핑

1. 조인 매핑

  • 데이터를 저장할 때 INSERT QUERY가 2번 불린다. (Item -> Movie)
  • 외래 키 참조 무결성 제약조건 활용가능하다.
  • 조회는 PK, FK로 Join해서 가져온다.
  • 운영하거나 작업하는 환경에서 DTYPE는 넣어주는 것이 좋다.
    • 컬럼명은 name 속성으로 바꿀 수 있다.
    • 관례상 디폴트 값(DTYPE)을 사용하는 것이 좋다.
    • @DiscriminatorColumn 이 없어도 작동한다.
  • 조회 시 부모 테이블만 보고 구분자 컬럼을 통해 조회하면 되므로 설계가 매우 깔끔해진다.
  • 테이블이 정규화되있어 저장공간이 효율적으로 관리된다.

2. 단일 테이블 전략

  • 논리 테이블을 하나로 합친다.
    (부모 테이블에 자식 속성들을 다 때려 넣는다.)
  • 부모 테이블 속성 중 컬럼(DTYPE)으로 자식들의 속성을 구분
  • @DiscriminatorColumn 이 반드시 있어야 한다.
  • 데이터 저장시 INSERT QUERY가 1번 불리고, Join할 필요도 없어 성능이 좋아진다.
  • DTYPE 생략이 가능하지만 운영상 있는게 좋다.
  • 모든 자식 객체가 하나의 테이블을 사용하므로 부모 테이블 속성 외 모든 자식 속성들은 null 을 허용해야 한다.
    • 이는 데이터 무결성 입장에서는 좀 애매하다.
  • 변경이라는 관점에서 볼 때 새로운 타입이 추가가 되면 많은 것들을 수정해야 한다.

JPA의 기본 전략은 단일 테이블 전략이다.

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

  • 테이블을 구현할 때 각각 부모 속성을 갖게 한다.
  • 단순하고 성능이 좋다.
  • @DiscriminatorColumn 이 의미가 없다.
  • 굳이 테이블이 생성될 필요가 없으므로 부모 클래스를 추상 클래스로 만든다.
  • 조회 시, 별도의 구분자 컬럼(DTYPE)이 없으므로 저장된 모든 객체들을 다 조회하는데 이는 매우 비효율적이다.
  • 그냥 쓰지 말자.
  • ORM 전문가와, DB 설계자 모두 안좋아하는 방식
  • 딱 봐도 안좋아 보이는 방식이다.
  • 새로운 자식 객체가 생길 때 마다 비지니스 로직의 세부적인 수정이 필요하다.
  • 다시 한번 말하지만 그냥 쓰지 말자.

정리

객체의 관점에서 보면 조인 전략이 가장 적합하고, 테이블 정규화도 잘 되있으며 설계 입장에서 깔끔하게 설계가 된다.
따라서, 조인 전략이 정석이라고 생각하면 된다.

기본적으로 조인 전략을 깔고, 정말 단순하고 확장 가능성이 없는 것들은 단일 테이블 전략을 사용한다.
비지니스 전략에서 매우 중요한 역할을 하면 조인 전략을 사용한다.

구현 클래스마다 테이블 전략은 그냥 생각도 하지말자. 나중에 엄청 후회하게 된다..

전략은 부모 클래스에서 어노테이션으로 설정한다.
만약 JPA를 사용하지 않으면 전략을 바꿀 때 엄청 많은 소스 코드(쿼리) 수정이 필요하지만, JPA를 사용하여 어노테이션 하나만으로 이를 매우 편리하게 바꿀 수 있다.

이를 통해 객체지향의 다형성을 활용하여 다양한 비즈니스를 쉽게 구현할 수 있다.


@MappedSuperclass

  • 공통적인 매핑 정보가 필요할 때 사용한다.
  • 객체입장에서 특정 속성을 상속받고 싶은 경우 사용한다.
    (등록, 수정, 삭제 등에서 항상 생성/수정 날짜를 넣어야 하는 경우를 생각해보자.)
  • 전체적으로 공통적으로 사용할 속성들을 넣을 때 사용한다.
  • 상속관계 매핑이 아니며 엔티티도 아니다(@Entity 사용 X)
  • 조인 전력은 실제 데이터베이스 테이블을 분리하거나 나누게 되는 반면 @MappedSuperclass 는 객체 입장에서 데이터만 상속하고 실제 테이블을 손대지 않는다.
  • 직접 생성해서 사용할 일이 없으므로 추상 클래스 권장한다.

참고
@Entity 클래스는 엔티티나 @MappedSuperclass로 지 정한 클래스만 상속 가능하다.

참고
@MappedSuperclass는 인터페이스로 사용할 수 없다.
혹시 된다고 하더라도 인터페이스에는 필드를 정의할 수 없기 때문에 무의미하다.
(이는 자바의 인터페이스와 추상 클래스의 차이점을 알면 당연하다.)

이미 상속을 받고 있을 때 추상 클래스 상속이 안되는 것은 자바 언어에서 막아두었기 때문에 새로운 추상 클래스를 만들어서 새로운 추상 클래스가 기존 추상 클래스를 상속 받는 식으로 구현해야 한다.

0개의 댓글