Backend/JPA

[JPA/Java Persistence API] 고급매핑

냠냠:) 2021. 6. 3. 14:14

[우아한형제들 김영환님의 인프런 강의 자바 ORM 표준 JPA 프로그래밍 - 기본편을 수강하고 정리한 내용입니다]


 

학습목표

  • 상속관계 매핑
  • @MappedSuperclass

 

상속관계 매핑

  • 관계형 데이터베이스는 상속 관계가 없다
  • 슈퍼타입 서브타입 관계라는 모델링 기법이 객체 상속과 유사 (ISA)
  • 상속관계 매핑 : 객체의 상속과 구조와 DB의 슈퍼타입 서브타입 관계를 매핑

 

상속관계 매핑 종류

슈퍼타입 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법

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

 

주요 어노테이션

  • Inheritance(starategy = InheritanceType.XXX)
  • JOINED : 조인전략
  • SINGLE_TABLE : 단일 테이블 전략
  • TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
  • @DiscriminatorColumn(name = "DTYPE")
  • @DiscriminatorValue("XXX")

(예시) 아이템 -> 책 상속관계 표현(조인전략 사용)

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public abstract class Item{
	@Id
	@GeneratedValue
	@Column(name = "ITEM_ID")
	private Long id;

	private String name;

	private Integer price;

	private Integer stockQuantity;
}
@Entity
@DiscriminatorValue("book")
public class Book extends Item {
	private String name;
    
	private String isbn;
}

 

 


조인 전략

엔티티에 해당하는 테이블을 모두 만들고 자식 테이블에서 부모 테이블의 기본키 외래키로 가지고 있는 모델

  • 테이블은 타입 개념이 없으므로 @DiscriminatorColumn 어노테이션을 통해 타입을 정해줘야함
  • 타입을 정해주지 않는다면, 특정 자식테이블의 데이터를 Item과 조인해서 조회할 수 없음

**getter/setter 생략

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

	@Id @GeneratedValue
	@Column
	private Long id;

	private String name;
	private int price;
}
@Entity
@DiscriminatorValue("movie")
public class Movie extends Item{

	private String director;
	private String actor;
}
public static void main(String[] args) {
	EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-application");
	EntityManager em = emf.createEntityManager();

	EntityTransaction tx = em.getTransaction();
	tx.begin();
	try {
		Movie movie = new Movie();
		movie.setDirector("춘식");
		movie.setActor("라이언");
		movie.setName("춘식과 라이언");
		movie.setPrice(10000);

		em.persist(movie);

		tx.commit();
	} catch (Exception e) {
		tx.rollback();
	}
	em.close();
	emf.close();
}

console
H2 DB 결과

 

장점

  • 테이블 정규화
  • 외래 키 참조 무결성 제약조건 활용
  • 저장공간 효율화 (다른 자식의 컬럼이 없으므로 null값 최소화)

단점

  • 조회시 조인을 많이 사용, 성능 저하(큰 차이는 없음)
  • 조회 쿼리가 복잡함
  • 데이터 저장시 INSERT SQL 2번 호출

단일 테이블 전략

테이블 하나에 부모 테이블의 공통 컬럼, 자식 테이블의 컬럼들을 모두 넣은 다음 "DTYPE" 컬럼으로 자식을 구별

 

아래 InheritanceType만 수정하면 바로 적용 가능 (메인 메서드도 동일)

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)		
@DiscriminatorColumn		
public abstract class Item {

	@Id @GeneratedValue
	@Column
	private Long id;

	private String name;
	private int price;
}

 

create 문 - 자식 테이블의 컬럼을 하나의 테이블에 전부 넣는 것을 볼 수 있다.
Insert 문
H2 DB 결과

장점

  • 조인이 필요 없으므로 일반적으로 조회 성능이 빠름
  • 조회 쿼리가 단순함

단점

  • 자식 엔티티가 매핑한 컬럼은 모두 null 허용
  • 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다. 상황에 따라 조회성능이 오히려 느려질 수 있다

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

부모 테이블의 컬럼을 포함한 자식 테이블들을 각자 생성

** @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)  적용 외 소스동일

**단점이 치명적이기 때문에 데이터 베이스 설계자와 ORM 전문가 둘 다 추천 X

 

create 문 - 부모 테이블 컬럼을 각각 자식테이블에 넣어 관리한다

 

Insert 문
H2 DB 결과

장점

  • 서브 타입을 명확하게 구분해서 처리할 때 효과적
  • not null 제약조건 사용 가능

단점

  • 여러 자식 테이블을 조회할 때 성능이 느림(Union 연산 필요)
  • 자식 테이블을 통합해서 쿼리하기 어려움

 


 

 

@MappedSuperclass

공통 매핑 정보가 필요할 때 사용

  • 상속관계 매핑 X -> @MappedSuperclass 어노테이션이 붙은 클래스는 엔티티가 아님
  • 엔티티X, 테이블과 매핑X
  • 부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공
  • 조회, 검색 불가(em.find(e))불가
  • 직접 생성해서 사용할 일이 없음 -> 추상클래스로 생성 권장

- 테이블과 관계가 없고 단순히 엔티티가 공통으로 사용하는 매핑정보(컬럼)을 모으는 역할

- 주로 등록일, 수정일, 등록자, 수정자 같이 엔티티 전체에서 사용하는 공통 컬럼들을 적용할 때 사용

** @Entity 클래스는 엔티티나 @MappedSuperclass로 지정한 클래스만 상속 가능

@MappedSuperclass
public abstract class BaseEntity {

	@Column(columnDefinition = "varchar(10)")
	private String createdBy;
	@Column(columnDefinition = "varchar(10)")
	private String updatedBy;
	private LocalDateTime createdTime;
	private LocalDateTime updatedTime;
}
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn
public abstract class Item extends BaseEntity{

	@Id @GeneratedValue
	@Column
	private Long id;

	private String name;
	private int price;
}

create - MappedSuperclass를 상속받은 Item Entity
Insert문 - BaseEntity 내용까지 추가

 

반응형