본문 바로가기
Back-End/자바 ORM 표준 JPA 프로그래밍

[JPA] 자바 ORM 표준 JPA 프로그래밍_7장

by ChaSso 2023. 6. 24.

7장 고급 매핑

 

7.1 상속 관계 매핑

∘ 관계형 데이터베이스에는 객체지향 언어에서의 상속과 같은 개념이 없음

∘ ORM에서의 상속 관계 매핑은 객체의 상속 구조와 데이터베이스의 슈퍼타입 서브타입 관계를 매핑하는 것

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

  - 각각의 테이블로 변환 : 각각을 모두 테이블로 만들고 조인 사용해서 조회. 조인 전략.

  - 통합 테이블로 변환 : 테이블 하나만 사용해서 통합. 단일 테이블 전략.

  - 서브타입 테이블로 변환 : 서브 타입마다 하나의 테이블 만듦. 구현 클래스마다 테이블 전략.

 

 

7.1.1 조인 전략

∘ 조인 전략 : 엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본 키를 받아서 기본 키 + 외래 키로 사용

∘ 테이블의 타입을 나타낼 수 있는 컬럼 필요

∘ 자식 테이블의 기본 키 컬럼명은 @PrimaryKeyJoinColumn을 사용해서 변경할 수 있음

 

∘ 장점

  - 테이블이 정규화됨

  - 외래 키 참조 무결성 제약조건을 활용할 수 있음

  - 저장공간을 효율적으로 사용함

 

∘ 단점

  - 조회할 때 조인이 많이 사용되어 성능이 저하될 수 있음

  - 조회 쿼리가 복잡함

  - 데이터를 등록할 INSERT SQL을 두 번 실행

 

∘ 관련 어노테이션 : @PrimaryKeyJoinColumn, @DiscriminatorColumn, @DiscriminatorValue

 

7.1.2 단일 테이블 전략

∘ 구분 컬럼(DTYPE)으로 어떤 자식 데이터가 저장되었는지 구분

∘ 조회할 때 조인을 사용하지 않아서 일반적으로 가장 빠름

∘ 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 됨

 

∘ 장점

  - 일반적으로 조회 성능 좋음

  - 조회 쿼리가 단순함

 

∘ 단점

  - 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 함

  - 테이블이 한 개이므로 테이블이 커질 수 있음

 

∘ 구분 컬럼을 꼭 사용해야 함 = @DiscriminatorColumn을 필수로 설정해야 함

 

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

∘ 자식 엔티티마다 테이블을 만듦

 

∘ 장점

  - 서브 타입을 구분해서 처리할 때 효과적

  - not null 사용할 수 없음

 

∘ 단점

  - 여러 자식 테이블을 함께 조회할 때 성능이 안 좋음

  - 자식 테이블을 통합해서 쿼리하기 어려움

 

∘ 구분 컬럼을 사용하지 않음

 

 

7.2 @MappedSuperClass

∘ 실제 테이블과 매핑되지 않음. 매핑 정보를 상속할 목적으로만 사용됨.

∘ 부모로부터 물려받은 매핑 정보 재정의 : @AttributeOverrides, @AttributeOverride

∘ 연관관계 재정의 : @AssociationOverrides, @AssociationOverride

∘ @MappedSuperclass로 지정한 클래스는 엔티티가 아니므로 em.find()나 JPQL에서 사용할 수 없음

∘ 이것보다 추상 클래스로 만드는 것을 권장

 

 

7.3 복합 키와 식별 관계 매핑

7.3.1 식별 관계 VS 비식별 관계

∘ 데이터베이스 테이블 사이에 관계는 외래 키가 기본 키에 포함되는지 여부에 따라 식별 관계, 비식별 관계로 구분됨

 

∘ 식별 관계 : 부모 테이블의 기본 키를 내려받아서 자식 테이블의 기본 키 + 외래 키로 사용하는 관계

∘ 비식별 관계 : 부모 테이블의 기본 키를 받아서 자식 테이블의 외래 키로만 사용하는 관계

  - 필수적 비식별 관계 : 외래 키에 NULL을 허용하지 않음. 연관관계를 필수적으로 맺어야 함.

  - 선택적 비식별 관계 : 외래 키에 NULL을 허용함. 연관관계를 맺을지 말지 선택 가능.

 

∘ 일반적으로 주로 비식별 관계를 사용하고 꼭 필요한 곳에만 식별관계 사용

 

7.3.2 복합 키: 비식별 관계 매핑

∘ 두 개 이상의 식별자를 사용하려면 별도의 식별자 클래스를 만들어야 함

∘ 별도의 식별자 클래스에 equals, hashCode 구현해야 됨

 

∘ @IdClass

  - PARENT 테이블의 기본 키가 복합 키로 구성되어 있으므로 복합 키 매핑을 위해 식별자 클래스 생성 필요

  - 각각의 기본 키 컬럼에 @Id → ParentId 클래스에 @IdClass

 

  - @IdClass를 적용한 식별자 클래스

    - 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 같아야 함

    - Serializable 인터베이스 구현 필요

    - equals, hashCode 구현 필요

    - 기본 생성자 있어야 함

    - 식별자 클래스는 public이어야 함

 

∘ @EmbeddedId

  - @IdClass보다 객체지향적인 방법

  - Parent 엔티티에서 식별자 클래스를 직접 사용하고 @EmbeddedId를 적으면 됨

 

  - @EmbeddedId를 적용한 식별자 클래스

    - @Embeddable을 붙여야 됨

    - Serializable 인터페이스 구현 필요

    - equals, hashCode 구현 필요

    - 식별자 클래스는 public

 

∘ 복합 키와 equals(), hashCode()

  - 식별자 객체의 동등성 보장을 위해 복합 키는 equals(), hashCode()를 필수로 구현해야 됨

 

@IdClass vs @EmbeddedId

  - @EmbeddedId이 더 객체지향적이고 중복이 없지만 특정 상황에서 JPQL이 조금 더 길 수 있음

 

7.3.3 복합 키: 식별 관계 매핑

∘ 식별 관계에서 자식 테이블은 부모 테이블의 기본 키를 포함해서 복합 키를 구성해야 하므로 @IdClass나 @EmbeddedId를 사용해서 식별자를 매핑 해야 됨

 

@IdClass와 식별 관계

  - 기본 키와 외래 키를 같이 매핑해야 하므로 식별자 매핑 @Id와 연관관계 매핑 @ManyToOne을 같이 사용

@EmbeddedId와 식별 관계

  - @MapsId 사용

 

7.3.4 비식별 관계로 구현

∘ 식별 관계와 비교해보면 매핑이 쉽고 코드가 단순함

 

7.3.5 일대일 식별 관계

∘ 일대일 식별 관계는 자식 테이블의 기본 키 값으로 부모 테이블의 기본 키 값만 사용

  ⇒ 부모 테입르의 기본 키가 복합 키가 아니면 자식 테이블의 기본 키는 복합 키로 구성하지 않아도 됨

∘ 식별자가 컬럼 한 개면 @MapsId를 사용하고 속성 값 비워두면 됨

 

7.3.6 식별, 비식별 관계의 장단점

∘ 식별 관계는 부모 테이블의 기본 키를 자식 테이블로 전파하면서 자식 테이블의 기본 키 컬럼이 점점 늘어남

∘ 식별 관계는 2개 이상의 컬럼을 합해서 복합 기본 키를 만들어야 하는 경우가 많음

∘ 식별 관계를 사용할 때 기본 키로 비즈니스 의미가 있는 자연 키 컬럼을 조합하는 경우가 많음 ↔ 비식별

∘ 식별 관계는 비식별 관계보다 테이블 구조가 유연하지 못함

∘ 일대일 관계를 제외하고는 식별 관계는 노력이 더 필요함

∘ 비식별 관계는 JPA에서 대리 키 생성을 위한 편리한 방법 제공

 

 

7.4 조인 테이블

∘ 조인 컬럼 사용 : 외래 키 컬럼 사용해서 관리

∘ 조인 테이블 사용 : 별도의 테이블을 사용해서 연관관계 관리

∘ 기본적으로는 조인 컬럼 사용

∘ 객체와 테이블을 매핑할 때 조인 컬럼은 @JoinColumn으로 매핑, 조인 테이블은 @JoinTable로 매핑

∘ 조인 테이블은 주로 다대다를 일대다, 다대일로 풀 때 사용

 

7.4.1 일대일 조인 테이블

7.4.2 일대다 조인 테이블

7.4.3 다대일 조인 테이블

7.4.4 다대다 조인 테이블

 

7.5 엔티티 하나에 여러 테이블 매핑

@SecondaryTable

  - 속성 : name, pkJoinColumns

∘ 더 많은 테이블을 매핑하려면 @SecondaryTables 사용

∘ 테이블당 엔티티를 각각 만들어서 일대일 매핑하는 것을 권장

  - 원하는 부분만 조회 가능

 

 

7.3 복합 키와 식별 관계 매핑

7.3.1 식별 관계 vs 비식별 관계

 식별 관계 : 부모 테이블의 기본 키를 내려받아서 자식 테이블의 기본 키 + 외래키로 사용하는 관계

 비식별 관계 : 부모 테이블의 기본 키를 받아서 자식 테이블의 외래 키로만 사용하는 관계

  - 필수적 비식별 관계 : 외래 키에 Null 허용

  - 선택적 비식별 관계 :           "            불허

 

7.3.2 복합 키: 비식별 관계 매핑

 JPA에서 식별자를 둘 이상 사용하려면 별도의 식별자 클래스 생성 필요

  - 식별자 클래스에 equals와 hashCode 구현 필요

 @IdClass를 사용할 때의 식별자 클래스

  - 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 같아야 함

 @EmbeddedId의 식별자 클래스

  - @Embeddable을 붙여줘야 함

  - Serializable 인터페이스 구현 필요

  - equals, hashCode  구현 필요

  - 기본 생성자 있어야 함

  - public이어야 함

 

7.3.3 복합 키: 식별 관계 매핑

 @IdClass

  - 기본 키와 외래 키를 같이 매핑해야 하므로 @Id와  @ManyToOne을 같이 사용

 @EmbeddedId

  - @MapsId 사용

 

7.3.4 비식별 관계로 구현

 

7.3.5 일대일 식별 관계

 

7.3.6 식별, 비식별 관계의 장단점

 데이터베이스 설계 관점에서는 비식별 관계가 더 선호됨

 식별 관계는 자식 테이블의 기본 키 컬럼이 점점 늘어남

 식별 관계는 2개 이상의 컬럼을 합해서 복합 기본 키를 만들어야 하는 경우가 많음

 식별 관계의 자연 키 컬럼이 많이 전파되면 변경이 어려움

 

7.4 조인 테이블

 조인 컬럼 사용

 조인 테이블 사용

 

7.4.1 일대일 조인 테이블

 조인 테이블의 외래 키 컬럼 각각에 총 2개의 유니크 제약 조건을 걸어야 함

 @JoinTable 사용

 

7.4.2 일대다 조인 테이블

 조인 테이블의 컬럼 중 다(N)와 관련된 컬럼에 유니크 제약 조건을 걸어야 

 

7.5 엔티티 하나에 여러 테이블 매핑

 @SecondaryTable을 사용하여 한 엔티티에 여러 테이블 매핑 가능

 @SecondaryTable을 사용하면 항상 두 테이블을 조회하기 때문에 최적화가 어려움

   => @SecondaryTable을 사용해서 두 테이블을 하나의 엔티티에 매핑하는 것보다 테이블당 엔티티를 각각 만들어서 일대일 매핑하는 것이 권장됨