DB/JPA

[JPA] 연관관계 매핑 간단 정리

꾸준함. 2021. 8. 28. 19:18

개요

기존 포스팅 최하단에 비고로 테이블 중심 설계가 아닌 객체 중심으로 설계할 경우 발생할 수 있는 문제에 대해 살짝 언급했었습니다. (https://jaimemin.tistory.com/1899)

이번 게시글에서는 연관관계 매핑에 대해 간단하게 알아보고 왜 테이블 중심으로 설계해야 하는지 이해해보겠습니다.

 

1. 객체 중심으로 모델링할 경우 문제점

  • 객체를 테이블에 맞추어 모델링할 경우 참조 대신 외래 키 즉, Foreign Key를 그대로 사용
  • 이럴 경우 외래 키 식별자를 직접 다루는 것이 문제
  • 식별자를 직접 다루기 때문에 식별자로 다시 조회하는 상황이 발생하는데, 이런 방식은 객체지향적이지 않음
  • 정리를 하자면, 객체를 테이블에 맞추어 데이터 중심으로 모델링할 경우 협력 관계를 만들어낼 수 없음
  • 테이블은 Foreign Key로 Join을 통해 연관된 테이블을 찾아내고 객체는 참조를 통해 연관된 객체를 찾기 때문에 이러한 문제점이 발생

 

예제: 직원을 나타내는 클래스가 있고 해당 직원은 어떤 기업의 소속

 

 

 

기업과 직원을 등록하고 다시 조회하는 코드 (연관관계 X)

 

 

2. 단방향 연관관계 (객체 연관관계 사용) 

  • 기존 예제에서 사용한 직원, 회사 엔티티에 연관관계를 입혀보면
  • 회사에는 많은 직원들이 있고 대부분의 회사들은 겸업을 금지하므로 직원 : 회사 = N : 1
  • 기존에는 Foreign Key를 그대로 사용하는 것이 문제였으므로 이번에는 객체의 참조를 이용하고 이에 맞는 JPA 어노테이션을 적용 (@ManyToOne, @JoinColumn)
  • 연관관계를 적용함에 따라 직원 객체로부터 바로 기업을 찾아낼 수 있는 것을 확인할 수 있음

 

예제: 직원을 나타내는 클래스가 있고 해당 직원은 어떤 기업의 소속

 

 

 

기업과 직원을 등록하고 다시 조회하는 코드 (연관관계 O)

 

 

 

 

3. 양방향 연관관계

  • 단방향 연관관계 예제에서는 기업 엔티티를 통해 소속된 직원들을 찾을 수 없었지만
  • 양방향 연관관계를 적용할 경우 직원 엔티티를 통해 기업을 찾을 수도 있고 적절한 JPA 어노테이션을 통해 기업 엔티티를 통해 소속된 직원들을 찾을 수 있음 (@OneToMany, )

 

예제: 직원을 나타내는 클래스가 있고 해당 직원은 어떤 기업의 소속

 

 

 

기업과 직원을 등록하고 다시 조회하는 코드 (연관관계 O)

 

 

 

 

3.1 양방향 연관관계 = 단방향 연관관계 * 2

  • 객체와 테이블 간에 연관관계를 맺는 차이를 이해하는 것이 핵심
  • 단방향 연관관계의 경우 연관관계가 2개 (직원 > 기업, 기업 > 직원)
  • 양방향 연관관계의 경우 논리적으로는 연관관계가 1개 (직원 <-> 기업)
    • 하지만, 사실 양방향 관계는 서로 다른 단방향 관계가 2개인 상태
    • 따라서 객체를 양방향으로 참조하기 위해서는 단방향 연관관계를 2개 만들어야 함

 

3.2 테이블의 양방향 연관관계

  • 테이블은 외래 키, Foreign Key 하나를 통해 두 테이블의 연관관계를 맺음
  • 앞선 예제에서는 COMPANY 테이블의 COMPANY_ID 외래 키 하나를 통해 양방향 연관관계를 가짐

 

SELECT *
FROM EMPLOYEE
INNER JOIN COMPANY
ON EMPLOYEE.COMPANY_ID = COMPANY.COMPANY_ID

 

3.3 양방향 연관관계의 주인과 mappedBy 속성

  • 앞선 예제에서 외래 키인 COMPANY_ID를 통해 양방향 연관관계를 가지므로 DB 입장에서는 Employee 내 Foreign Key만 관리해주면 됨 
    • Employee 내 외래 키를 바꾸면 다른 기업을 참조
  • DB 입장에서는 양방향 연관관계 중 하나의 객체를 주인으로 지정하여 외래 키를 등록 및 수정하게 하는 것이 관리 측면에서 효율적
    • 주인이 아닌 쪽은 등록 및 수정이 불가하고 오로지 읽기만 가능
    • 읽기만 가능한 객체는 mappedBy 속성을 사용하고 등록 및 수정이 가능한 주인은 mappedBy 속성을 사용하지 않음
  • 정리를 하자면, 외래 키가 있는 객체 즉, Many 쪽을 무조건 연관관계의 주인으로 정하자
    • 비즈니스 로직을 기준으로 연관관계의 주인을 선택 X
  • 위 에제에서는 직원이 Many이므로 직원인 Employee 객체가 양방향 연관관계의 주인
  • 이론상 연관관계의 주인 쪽에만 연관관계를 맺은 객체를 넣어주면 되지만 순수한 객체 관계를 고려했을 때는 양쪽 객체에 모두 값을 입력해주는 것이 맞음 (테스트 케이스 작성할 때 훨씬 수월함)

 

 

* 양방향 매핑 시 toString(), lombok, JSON 생성 라이브러리를 사용할 경우 무한 루프가 발생할 수 있으므로 주의

 

비고

  • 앞서 JSON 생성 라이브러리를 사용할 경우 양방향 관계에서 무한 루프가 발생할 수 있다고 언급했지만 Controller에서 Entity를 직접 반환하지 않을 경우 문제 될 게 없음
    • Controller에서 Entity를 직접 반환할 경우 무한루프 위험뿐만 아니라 필드 추가/삭제 시 API 스펙이 바뀔 수 있으므로 절대 Entity를 그대로 반환 X
    • 추천하는 방법은 별도 DTO를 생성해서 Entity를 API 스펙에 맞는 DTO로 변환 후 Controller에서 반환하는 방법
  • 양방향 매핑에 대해 알아봤지만 사실 단방향 매핑으로도 이미 연관관계는 완성된 상태
    • 우선, 단방향 매핑을 기준으로 DB를 설계한 이후
    • 단순 조회 기능을 목적으로 필요시 양방향 연관관계를 맺는 것을 추천
    • 현업에서는 JPQL 쿼리가 너무 복잡해질 경우 양방향 연관관계를 맺는 경우가 많음

 

출처

자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한 강사님)

 

반응형

'DB > JPA' 카테고리의 다른 글

[JPA] 상속관계 매핑  (2) 2021.09.07
[JPA] 다양한 연관관계 매핑  (0) 2021.08.31
[JPA] Entity 매핑 정리  (0) 2021.08.23
[JPA] PersistenceContext 간단 정리  (0) 2021.08.20
JPA를 학습해야하는 이유  (1) 2021.08.16