본문 바로가기

IT/JPA & Hibernate

[JPA] 상속 관계 매핑

1. 상속 관계 매핑이란?

슈퍼타입 테이블, 서브타입 테이블을 자바에서 상속관계인 것 처럼 사용하는 방법입니다.

 

2. 상속 관계 매핑 전략의 종류

1) JOINED (조인전략)

슈퍼타입과 서브타입을 식별관계로 사용하는 방법입니다.

 

2) SINGLE_TABLE (단일 테이블 전략)

슈퍼타입과 서브타입을 하나의 테이블로 생성하는 전략입니다.


3) TABLE_PER_CLASS (타입 별 테이블 생성 전략) (비추천)

파일 타입 별로 테이블을 생성하는 전략입니다.

3. 상속 관계 매핑 적용

1) FileInfo.java

import javax.persistence.*;

@Entity
@Table(name = "file_info")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "data_type")
public abstract class FileInfo {
    @Id
    @GeneratedValue
    private Long id;

    private String url;

    @Column(name = "org_name")
    private String orgName;

    private String length;
    
    /*
    setter, getter 생략
    */
}
슈퍼 타입 클래스입니다. JOINED 전략을 사용할 경우 슈퍼 타입과 서브 타입은 식별관계가 되므로 서브 타입은 슈퍼타입 기본키를 외래키로 가짐과 동시에 기본키로 선언합니다.

@Inheritance 어노테이션을 이용해 JOINED, SINGLE_TABLE, TABLE_PER_CLASS 전략을 선택할 수 있으며, JOINED 전략을 보통 사용합니다. 하지만 검색속도 최적화를 위해 SINGLE_TABLE 전략을 사용하기도 합니다.
(TABLE_PER_CLASS 전략은 웬만하면 사용하지 않는 것을 추천합니다.)

@DiscriminatorColumn 어노테이션은 JOINED, SINGLE_TABLE 전략일 경우 사용하며, 서브타입의 구분값을 저장하는 컬럼입니다. name 속성을 이용해 구분 컬럼의 이름을 지정할 수 있습니다.

 

2) Image.java, Sound.java, Video.java

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

@Entity
@DiscriminatorValue(value = "IMAGE")
public class Image extends FileInfo {

    private String type;

    private int width;
    private int height;
    
    /*
    setter,getter 생략
    */
}

@Entity
public class Sound extends FileInfo {

    private Long runtime;
    private String type;
    
    /*
    setter,getter 생략
    */    
}

@Entity
public class Video extends FileInfo {

    private Long runtime;

    private String type;
    
    /*
    setter,getter 생략
    */
}
서브 타입 클래스입니다. @DiscriminatorColumn 어노테이션을 사용했을 경우 서브타입 구분 값에 클래스 명이 저장됩니다.
@DiscriminatorValue 어노테이션을 사용했을 경우 서브타입 구분 값을 지정할 수 있습니다.

 

4. 테스트

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();

        tx.begin();
        try {
            Image image = new Image();

            image.setOrgName("google_icons.png");
            image.setUrl("https://ssl.gstatic.com/gb/images/p1_c9bc74a1.png");
            image.setType("png");

            //image 영속화
            em.persist(image);
            
            // 쓰기 지연에 쌓아둔 SQL을 DB에 전송한다.
            em.flush();
            // 영속성 캐시를 제거한다.
            em.clear();

            //image 조회
            Image findImage = em.find(Image.class, image.getId());

            System.out.println(findImage.getUrl());
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();

    }
}

 

@Inheritance(strategy = InheritanceType.JOINED) 전략으로 테스트했으며, Image를 저장하면 file_info와 image 테이블에 각각 저장됩니다. 

그리고 image를 조회할 경우 file_info와 image 테이블을 조인해서 select 합니다. 

 

# commit 시 작동되는 쿼리

# Image 저장 시, file_info와 image 테이블에 각각 저장한다.
        insert 
        into
            file_info
            (length, org_name, url, data_type, id) 
        values
            (?, ?, ?, 'IMAGE', ?)
		
        insert 
        
        into
            Image
            (height, type, width, id) 
        values
            (?, ?, ?, ?)
            
# image 조회 시, image 테이블과 file_info 테이블을 조인해서 select한다             
    select
        image0_.id as id2_0_0_,
        image0_1_.length as length3_0_0_,
        image0_1_.org_name as org_name4_0_0_,
        image0_1_.url as url5_0_0_,
        image0_.height as height1_1_0_,
        image0_.type as type2_1_0_,
        image0_.width as width3_1_0_ 
    from
        Image image0_ 
    inner join
        file_info image0_1_ 
            on image0_.id=image0_1_.id 
    where
        image0_.id=?            

도움이 되셨다면 공감 버튼 한번씩 눌러주세요!