본문 바로가기
프로그래밍/Back-end

JPA 상속관계 매핑

by @GodWin 2024. 10. 11.

-

-

안녕하세요? 오늘은, JPA의 고급매핑 중에서, 상속관계 매핑에 대해서 알아보도록 하겠습니다.

-

상속관계 매핑이란?


: 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑
: @Ingeritance 를 사용해서 전략 설정

※ 객체는 상속관계가 존재하지만, 관계형 데이터베이스에는 상속관계가 존재하지 않습니다.
그나마, 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사합니다.


상속관계 매핑은 조인 전략, 단일 테이블 전략, 구현 클래스마다의 테이블 전략 세가지가 존재합니다.

 

-

조인 전략

 

: 각각 테이블로 변환해서, 조인으로 관리하고자하는 전략
: 가장 정규화된 전략
: 외래 키 참조 무결성 제약조건 활용 가능 (타 테이블에서 데이터 조회 시 설계가 깔끔)
: 저장공간의 효율화 최대

: 조회시 조인을 많이 사용
> 조회 쿼리가 복잡
: 데이터 저장시 쿼리가 두번 호출

하지만, 가장 정석적인 방법으로 통한다.




예로 들어서, 물품 테이블에, 음반 / 영화 / 책 등의 하위 테이블이 존재한다고 가정해 보도록 하겠습니다.


+
조인전략은, 각각의 테이블을 조인해서, 상속관계를 매핑하도록 하는 전략입니다.


물품 엔티티 생성)

@Entity
// 전략 설정 @DiscriminatorColumn
// DTYPE 컬럼 생성 후, 엔티티 명이 들어가게 된다.
@Ingeritance(straregy = IngeritanceType.JOINED) 
public abstract class Item {
  @Id @GeneratedValue
  @Column(name = "ITEM_ID")
  private Long id;
  
  @Column(name = "ITEM_NAME")
  private String name;
  
  @Column(name = "ITEM_PRICE")
  private int price;
  
  ...
  
}


음반 엔티티 생성)

@Entity
public class Album extends Item {
  @Column(name = "ARTIST")
  private String artist;
  
  ...
  
}


영화 엔티티 생성)

@Entity
public class Movie extends Item {
  @Column(name = "DIRECTOR")
  private String director;
  
  @Column( name = "ACTOR") 
  private String actor; 
  
  ...
  
}


책 엔티티 생성)

@Entity
public class Book extends Item { 
  
  @Column(name = "AUTHOR") 
  private String author;
  
  @Column(name = "ISBN")
  private String isbn; 
  
  ... 
  
}

 

샘플코드)

EntityManagerFactory emf = Persistence.createEntityManagerFactory("유닛명"); 

EntityManager em = emf.createEntityManager(); 
EntityTransaction tx = em.getTransaction();

tx.begin();

Movie movie = new Movie(); 
movie.setDirector("봉준호");
movie.setActor("송강호");
movie.setName("기생충");
movie.setPrice(30000);
em.persist(movie); 

// 영속성 클리어
em.flush(); 
em.clear(); 

// 조인해서 Item의 movie를 가지고 온다. 
Movie findMovie = em.find(Movie.class, movie.getId()); 

System.out.println("findMove : " + findMovie); 

tx.commit();



DB 결과) item 테이블

ITEM_ID ITEM_NAME ITEM_PRICE DTYPE
1 기생충 30000 Movie


DB 결과) movie 테이블

DiRECTOR ACTOR ID (FK)
봉준호 송강호 1



-

단일테이블 전략

 

: 통합 테이블로 변환해서 관리 (하나의 테이블로 생성 관리)
    > Insert가 하나의 쿼리로 실행
    > Join도 불필요
    > 관리가 용이

: 자식 엔티티가 매핑한 컬럼은 모두 Null 허용
: 단일 테이블에 모든것을 저장하기 때문에, 테이블이 커질 수 있다.
    > 상황에 따라 성능 저하 초래




물품 엔티티 생성)

@Entity
@Ingeritance(straregy = IngeritanceType.SINGLE_TABLE) // 전략 설정 
//@DiscriminatorColumn // 단일테이블전략은 해당 어노테이션 불필요 
public abstract class Item {
  
  @Id @GeneratedValue
  @Column(name = "ITEM_ID") 
  private Long id;
  
  @Column(name = "ITEM_NAME") 
  private String name; 
  
  @Column(name = "ITEM_PRICE")
  private int price; 
  
  ... 
  
}


음반 엔티티 생성)

@Entity 
public class Album extends Item {

  @Column(name = "ARTIST") 
  private String artist; 
  
  ...
  
}


영화 엔티티 생성)

@Entity 
public class Movie extends Item {

  @Column(name = "DIRECTOR")
  private String director;
  
  @Column( name = "ACTOR")
  private String actor;
  
  ... 
  
}


책 엔티티 생성)

@Entity 
public class Book extends Item {

  @Column(name = "AUTHOR")
  private String author;
  
  @Column(name = "ISBN") 
  private String isbn; 
  
  ... 
  
}

 

샘플코드)

EntityManagerFactory emf = Persistence.createEntityManagerFactory("유닛명");

EntityManager em = emf.createEntityManager(); 
EntityTransaction tx = em.getTransaction(); 

tx.begin(); 

Movie movie = new Movie(); 
movie.setDirector("봉준호"); 
movie.setActor("송강호");
movie.setName("기생충"); 
movie.setPrice(30000); 

em.persist(movie); 

tx.commit();



DB 결과) Item 테이블만 생성 및 관리

DTYPE ITEM_ID ITEM_NAME ITEM_PRICE ARTIST AUTHOR ISBN ACTOR DIRECTOR
Movie 1 기생충 30000 null null null 송강호 봉준호



-

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

 

: 서브타입 테이블로 변환
: 부모 테이블이 없이, 각각의 테이블 PK로 관리
: Not Null 제약조건 사용 가능
: 데이터를 조회할 때, UNION으로 전체 테이블을 조회하게 된다.
    > 비효율적으로 동작
: 자식 테이블을 통합해서 쿼리하기가 어렵다.



> 절대비추천 

물품 엔티티 생성)

@Entity 
@Ingeritance(straregy = IngeritanceType.TABLE_PER_CLASS) // 전략 설정
public abstract class Item {

  @Id @GeneratedValue 
  @Column(name = "ITEM_ID") 
  private Long id; 
  
  @Column(name = "ITEM_NAME") 
  private String name; 
  
  @Column(name = "ITEM_PRICE") 
  private int price;
  
  ... 
  
}


음반 엔티티 생성)

@Entity
public class Album extends Item {

  @Column(name = "ARTIST") 
  private String artist;
  
  ... 
  
}

 

영화 엔티티 생성)

@Entity 
public class Movie extends Item { 

  @Column(name = "DIRECTOR")
  private String director; 
  
  @Column( name = "ACTOR") 
  private String actor; 
  
  ... 
  
}


책 엔티티 생성)

@Entity 
public class Book extends Item { 

  @Column(name = "AUTHOR")
  private String author;
  
  @Column(name = "ISBN")
  private String isbn;
  
  ...
  
}




샘플코드)

EntityManagerFactory emf = Persistence.createEntityManagerFactory("유닛명"); 

EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction(); 

tx.begin(); 

Movie movie = new Movie(); 
movie.setDirector("봉준호");
movie.setActor("송강호"); 
movie.setName("기생충"); 
movie.setPrice(30000); 

em.persist(movie); 

tx.commit();


DB결과) Movie 테이블

ITEM_ID ITEM_NAME ITEM_PRICE ACTOR DIRECTOR
1 기생충 30000 송강호 봉준호

 



오늘은, JPA의 고급매핑 중에서, 상속관계 매핑에 대해서 알아보았습니다.
그럼 오늘도 즐거운 하루 되시길 바라겠습니다.