250x250
250x250
JinSeopKim
Hello World!
JinSeopKim
전체 방문자
오늘
어제
  • 분류 전체보기 (168)
    • Artificial intelligence (14)
      • DeepDiveToAI (3)
      • Pytorch (3)
      • Etc (8)
    • Back-end (19)
      • Spring (10)
      • JPA (9)
    • Language (24)
      • Python (3)
      • Java (11)
      • Swift (10)
    • Math (4)
      • Linear Algebra (4)
    • CodingTest (79)
      • Algolithm (12)
      • Backjoon (25)
      • Programmers (42)
    • Etc (27)
      • Book Review (3)
      • Adsp (6)
      • Life (2)
      • Docker (1)
      • odds and ends (15)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • GitHub

인기 글

태그

  • 개발
  • data
  • uArm
  • 문제풀이
  • 구현
  • 브루트포스
  • certificate
  • AI
  • Front-end
  • DP
  • ios
  • 카카오
  • 자바
  • JAVA8
  • Python
  • java
  • 파이썬
  • 프로그래머스
  • 알고리즘
  • BOJ
  • JPA
  • 백준
  • 머신러닝
  • swift
  • BFS
  • ADsP
  • 코딩테스트
  • 선형대수
  • 개발자
  • SpringMVC

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
JinSeopKim

Hello World!

JPA 상속관계 매핑하기(+ @MappedSuperclass)
Back-end/JPA

JPA 상속관계 매핑하기(+ @MappedSuperclass)

2022. 1. 16. 22:38
728x90
728x90

도입

지난 시간에 JPA를 활용해 객체와 연관관계 매핑을 하는 방법을 알아보았다. 이번 시간에는 JPA를 활용하여 객체의 상속관계를 테이블로 표현하는 방법에 대하여 알아보고, 상속관계와는 다르지만 비슷해서 혼동하기 쉬운 개념인 @MappedSuperclass를 알아보도록 하겠다.


상속관계 매핑

객체지향언어에서는 중복되는 정보를 상속관계를 사용해 묶어줄 수있다. 예를들어 사람과 강아지 고양이는 모두 이름과 나이 그리고 구분지어줄 ID를 가지고 있다. 이러한 특징을 '동물'로 묶어서 상속해줄 수 있다.

객체에서는 이렇게 상속을 허용해주지만, 테이블에서는 이렇게 상속을 할 수 없다. 따라서 상속을 위해서는 전략을 사용해야한다. 

상속의 전략을 사용하기 위해서는 @Inheritance annotation을 이용하여 strategy값을 넣어주면 된다. 추가적으로 자주 사용되는 Annotation으로 @DiscriminatorColumn(name="xx")이 있으며 이것은 어느 테이블과 매핑이 되어있는지에 대한 정보를 상위 테이블에 저장해두는 것이다. 만약 동물 테이블이 사람과 연관되어있는 것이라면 동물에 DTYPE으로 사람이 들어가게 된다.(Default) name의 값을 변경하면 그 값이 DTYPE이 된다. 그리고 @DiscriminatorValue("xx")를 사용해주면 DTYPE으로 입력되는 엔티티의 이름을 변경해줄 수 있다.(Default는 엔티티 테이블 이름이다.)JSP에서는 3가지의 전략을 제공하며 3가지에 대하여 자세히 알아보도록 하겠다.

  1. Join을 활용하여 상속관계 매핑(JOINED)
  2. 단일 테이블로 매핑(SINGLE_TABLE)
  3. 각 테이블로 매핑(TABLE_PER_CLASS)

Join을 활용하여 상속관계 매핑하기

Join을 활용하여 매핑을 하는 것은 말그대로 엔티티의 조인을 활용해주는 것이다. 사람과 강아지 그리고 고양이에 동물과 연관된 ID를 넣어주어 매핑을 할 수 있게 만들어 주는 전략이다. 그렇게 되면 사람 강아지 고양이에는 ID라는 PK이자 FK가 생성된다. 이 전략을 사용하면 객체와 굉장히 유사하게 매핑을 할 수 있다. 그리고 테이블이 정규화가 되어있다.(같은 것 끼리 묶여있음) 그리고 외래키 참조 무결성 제약조건을 사용할 수 있다.(참조할 수 없는 값을 가질 수 없음) 그리고 뒤에서 소개할 Single Table에 비해 저장공간을 효율적으로 사용한다.

 

하지만 단점으로 조회를 할 때마다 조인을 사용하기 때문에 성능이 저하될 수 있다. 그리고 데이터를 저장하게 되면 항상 동물과 아래 엔티티 두개의 Insert sql이 날라가게 된다.

 

@DiscriminatorColumn을 붙여주어야 동물 Entity에 DTYPE으로 어느 엔티티와 매핑이 되었는지 정보를 제공해준다.

단일 테이블로 매핑하기

단일 테이블로 매핑하는 것은 테이블 한곳에 위 정보를 모두 넣어주는것을 말한다. 즉 동물 테이블 안에 사람과 고양이 그리고 강아지의 특징을 모두 넣어주고 만약 사람을 사용한다면 강아지와 고양이에 대한 정보는 null로 남겨주는 것이다. 단일 테이블로 매핑하면 매우 간단하고, 따로 조회를 하거나 할 때 조인도 일어나지 않기 때문에 성능도 빠르다. 하지만 단점으로 모든 자식 엔티티의 매핑 컬럼에 null값이 올 수 있도록 세팅을 해주어야하며, 모든 것을 한 테이블에 때려박으므로 조인 방식에 비해 비교적 공간을 많이 잡아먹는다.

 

그리고 @DiscriminatorColumn(name="xx")를 사용하지 않아도 DTYPE값이 들어간다. 왜냐하면 어느 값이 매핑되어있는지 모르기 때문이다. 

 

실무에서는 Join과 단일 테이블 매핑 둘중에 하나만 사용하므로 두개를 비교해서 알아보겠다.

  Join으로 매핑 단일 테이블로 매핑
조회 성능 느림 빠름
메모리 사용 적절함 많음
단점 조회시 조인을 너무 많이 함 자식 엔티티 칼럼 모두 null을 허용함

기본적으로 Join을 사용하는 것이 테이블도 정규화되어있고 저장공간도 효율적으로 사용할 수 있으므로 괜찮은 것 같다. 그리고 단일 테이블 매핑의 경우 만약 칼럼이 엄청 많다면, 오히려 Join을 하는 것보다 메모리 낭비로 인해 더 느려질 수 있을 것 같다. Join을 사용하지만 매우 간단하고 미래를 봤을 때 크게 변화할 가능성이 적어보이는 간단한 상속관계는 단일테이블전략을 사용해주는 방식으로 선택해야할 것 같다.

각 테이블로 매핑하는 전략

실무에서는 사용하지 않지만 간단히 알아보겠다.

동물 테이블 즉 상위 클래스의 엔티티 테이블의 정보를 사람, 고양이, 그리고 강아지에 넣어 각각을 구현하는 방법이다. 이렇게 구현을 하면 

서브타입을 명확히 구분하여 처리가 가능하며 싱글테이블전략에서 사용하지 못하였던 not null 제약조건을 사용할 수 있다.

 

하지만, 만약 자식에 대하여 찾는게 아닌 부모(동물클래스)에 대하여 찾을 때는 모든 자식 클래스를 Union하여 찾아주어야하므로 성능이 굉장히 느려진다.

상속관계에서 보여지는 JPA의 위대함

상속관계를 어떤 전략을 사용하느냐에 따라 테이블이 달라지는 것을 알 수 있다. 테이블이 달라지면, 그 테이블을 생성하거나 하는 모든 코드를 변경해 주어야 하므로 매우 번거로울 것이다. 하지만 JPA로 이러한 일들을 처리하면 @Inheritance의 strategy 값만 변경하여주면 손쉽게 해결해 줄 수 있다. 

@MappedSuperclass

MappedSuperclass는 상속관계 매핑이 아니다!! 하지만 너무 비슷하여 혼동할 수도 있기 때문에 이번시간에 다루어보려고 한다.

엔티티에 중복적으로 들어가는 데이터로 ID가 있을 수 있다. 그리고, 객체를 언제 생성하였는지? 누가 생성하였는지, 누가 변경하였는지, 언제 마지막으로 변경하였는지 등에 대한 정보를 넣어주고 싶을 때가 있을 것이다. 이 때 일일이 모든 클래스를 들어가서 Entity를 수정해주면 된다. 하지만 이것은 매우 비효율적이다. 이렇게 중복적으로 대부분의 엔티티에서 사용해주는 정보를 상속으로 해결해줄 수 있다. @MappedSuperclass를 사용해주면 된다. 이것은 엔티티가 아니며 테이블과 매핑도 되지 않는다. 단순히 상속받은 클래스에게 매핑되는 정보를 제공해주는 역할을 수행해준다. 

 

매핑정보만 제공해주기 때문에 @Entity나 @MappedSuperclass만 상속받을 수 있다.

 

직접 생성해서 사용하는 일이 없으므로 되도록 abstract 클래스로 생성하도록 하자.

import javax.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class BaseEntity {

    private String createdBy;
    private LocalDateTime createdDate;
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;
}

다른 Entity클래스에서 extends해주면 위에 대한 매핑정보를 받아와 사용하게 된다.

이 글은 김영한님의 강의 "자바 ORM 표준 JPA 프로그래밍"를 공부한 후 작성한 글 입니다.
728x90
728x90
저작자표시 비영리 (새창열림)

'Back-end > JPA' 카테고리의 다른 글

JPA 프록시 객체와 지연로딩  (0) 2022.02.02
JPA 연관관계 매핑하기  (0) 2022.01.15
JPA 기본 키 매핑하기  (0) 2022.01.12
JPA로 필드와 칼럼 매핑하는 annotation 알아보기  (0) 2022.01.10
JPA로 객체와 테이블 매핑하기  (0) 2022.01.07
    'Back-end/JPA' 카테고리의 다른 글
    • JPA 프록시 객체와 지연로딩
    • JPA 연관관계 매핑하기
    • JPA 기본 키 매핑하기
    • JPA로 필드와 칼럼 매핑하는 annotation 알아보기
    JinSeopKim
    JinSeopKim
    기록📚

    티스토리툴바