노트 정리/자바 ORM 표준 JPA 프로그래밍

[JPA이론] 7. 고급매핑

DuL2 2022. 10. 14. 19:22

상속관계 매핑

 관계형 데이터베이스는 상속 관계를 매핑할 수 없다. 그나마 관계형 데이터베이스에는 슈퍼타입 - 서브타입 관계가 존재하여 객체의 상속과 비슷하므로 이를 사용해 객체의 상속을 매핑할 수 있다.

 

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

  • 테이블 join 전략 사용 - 정규화된 방식
    • 물품 - 책, 영화, 음반 간의 부모 - 자식 관계가 있다면 각각의 테이블을 만들어 부모_ID를 FK로 만들어 조인하여 사용하는 방법.
  • 단일 테이블 전략 사용 - 보통 성능을 위한 방식
    • 통합 테이블을 구성하여 하위 테이블의 모든 컬럼을 넣는 방법
  • 서브타입 테이블 전략 사용 - 부모 테이블 없이 자식 테이블로만 정리
    • 구현 클래스마다 테이블 사용하는 방법

 

기본적으로 아무런 어노테이션이 없을 때는 단일 테이블 전략으로 만들어짐.

 

주요 Annotation

  • @Inheritance(strategy=InheritanceType.XXX)
    • JOINED: 조인 전략
      • 장점
        • 테이블 정규화
        • 외래 키 참조 무결성 제약조건 활용가능
        • 저장공간 효율화
      • 단점
        • 조회시 조인을 많이 사용 -> 성능저하 but, 조인에 따라서 성능저하가 작을 수 도 있음.
        • 조회 쿼리가 복잡함
        • 데이터 저장시 INSERT SQL 2번 호출
    • SINGLE_TABLE: 단일 테이블 전략
      • 장점
        • 조인이 필요 없으므로 일반적으로 조회 성능이 빠름
        • 조회 쿼리가 단순함
      • 단점
        • 자식 엔티티가 매핑한 컬럼은 모두 null 허용
        • 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있다. 상황에 따라서 조회 성능이 오히려 느려질 수 있다. -> 보통 이런 일이 생기기 힘듬.(임계점을 넘어야함)
    • TABLE_PER_CLASS: 구현 클래스마다 테이블 전략
      • 이 전략은 데이터베이스 설계자와 ORM 전문가 둘 다 추천X
      • 부모 클래스를 abstract로 만들시 부모 테이블이 생기지 않음. 
      • 장점
        • 서브 타입을 명확하게 구분해서 처리할 때 효과적
        • not null 제약조건 사용 가능
      • 단점
        • 여러 자식 테이블을 함께 조회할 때 성능이 느림(UNION SQL 필요) -> 1번 id를 찾으려면 자식 테이블 모두 찾아봐야함.
        • 자식 테이블을 통합해서 쿼리하기 어려움
  • @DiscriminatorColumn(name=“DTYPE”)
    • 어느 자식테이블과 조인되어 있는지 알려주는 컬럼의 이름을 설정하는 어노테이션
    • SINGLE_TABLE 전략일 때는 없어도 생성됨
  • @DiscriminatorValue(“XXX”)
    • DTYPE에 들어갈 자식 클래스의 이름을 지정하는 어노테이션

 

@DiscriminatorColumn(name=“DTYPE”)

 기본값으로 "DTYPE"이 지정된다. 없어도 작동하는데에는 문제없지만 DB에서의 작업할 때 쿼리가 어떤 것 때문에 나갔는지 확인할 수 있기 때문에 넣어두는 것이 좋다.

@DiscriminatorColumn 추가 전 @DiscriminatorColumn 추가 후

 

@DiscriminatorValue(“XXX”)

 사내 특정 DB 룰이 있어 변경해야 할 경우에 사용할 수 있다.

 만약 Album 클래스의 DTYPE을 A로 표시하고 싶다면 다음과 같이 작성하면 된다.

 

@Entity
@DiscriminatorValue(value = "A")
public class Album extends Item {
    private String artist;
    ...
}

위의 예제 영화로 변경하게 되면 다음과 같에 DB에 저장되게 된다.

 

Mapped Superclass - 매핑 정보 상속

 두 클래스, 두 테이블의 관계는 없지만 id, name과 같이 공통 속성이 존재할 때 사용하는 어노테이션이다.

 

 만약, 모든 엔티티에서 생성되고 수정된 시각과 생성자 및 수정자의 정보를 기입하도록 정책이 변경되었을 때 우리는 다음과 같은 정보들을 모든 엔티티에 일일히 넣어야할 것이다.

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

 이런 상황에서 `@MappedSuperclass` 어노테이션을 활용하여 처리할 수 있다.

 

먼저 다음과 같은 공통 속성이 추려진 클래스를 만들고 이 클래스의 속성을 사용하고 싶은 클래스에서 상속받으면 사용할 수 있다.

@MappedSuperclass
public abstract class BaseEntity {
    private String createdBy;
    private LocalDateTime createdDate;
    private String lastModifiedBy;
    private LocalDateTime lastModifiedDate;
...
}

 

 Mapped Superclass는 실제 엔티티가 아니므로 테이블이 생성되지 않는다. 부모 클래스를 상속받는 자식 클래스에게 속성 정보만 제공하기 때문에 EntityManager로 검색 조회가 불가능하다. 이 엔티티를 직접 사용할 일이 없으므로 추상 클래스로 작성하여 사용하자.