응애개발자
article thumbnail
Published 2023. 7. 13. 03:57
다양한 연관관계 매핑 Spring/JPA
728x90

1. 다대일

DB 테이블의 1 : N 관계에서 외래 키는 항상 다 쪽에 있다. 예를 들어 회원(N)과 팀(1)이 있으면 회원 쪽이 연관관계의 주인이다. 

 

다대일 단방향 [N : 1]

다대일 단방향

 

회원 엔티티
팀 엔티티

다대일 단방향 연관관계이다. Member.team 필드로 회원 테이블의 TEAM_ID 외래 키를 관리한다.

 

다대일 양방향 [N : 1 , 1 : N]

실선이 주인이고 점선은 주인이 아니다.

회원 엔티티
팀 엔티티

  • 양방향은 외래 키가 있는 쪽이 연관관계의 주인이다.
  • 양방향 연관관계는 항상 서로를 참조해야 한다.

 

2. 일대다

일대다 관계는 엔티티를 하나 이상 참조할 수 있으므로 자바 컬렉션인 Collection, List, Set, Map 중에 하나를 사용해야 한다.

 

일대다 단방향 [1 : N]

일대다 단방향
일대다 단방향 팀 엔티티
일대다 단방향 회원 엔티티

 

일대다 단방향 관계를 매핑할 때는 @JoinColumn을 명시해야 한다.

 

- 일대다 단방향 매핑의 단점

매핑한 객체가 관리하는 외래 키가 다른 테이블에 있다는 점이다. 본인 테이블에 외래 키가 있으면 엔티티의 저장과 연관관계 처리를 INSERT SQL 한 번으로 끝낼 수 있지만, 다른 테이블에 외래 키가 있으면 UPDATE SQL을 추가로 실행해야 한다.

일대다 단방향 매핑의 단점
실행결과 SQL

Member 엔티티는 Team 엔티티를 모르고, 연관관계 정보는 Team 엔티티의 members가 관리한다. 따라서 Member 엔티티를 저장할 때는 MEMBER 테이블의 TEAM_ID 외래 키에 아무 값도 저장되지 않는다. 대신 Team 엔티티를 저장할 때 Team.members의 참조 값을 확인해서 회원 테이블에 있는 TEAM_ID 외래 키를 업데이트한다.

 

일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자!

 

일대다 양방향 [1 : N, N : 1]

일대다 양방향 매핑은 존재하지 않고, 대신 다대일 양방향 매핑을 사용해야 한다. 다대일 관계는 항상 다 쪽에 외래키가 있기 때문에 @ManyToOne 에는 mappedBy 속성이 없다. 그렇다고 양방향 매핑이 완전히 불가능한 것은 아니다. 일대다 단방향 매핑 반대편에 같은 외래 키를 사용하는 다대일 단방향 매핑을 읽기 전용으로 하나 추가하면 된다.

일대다 양방향
일대다 양방향 팀 엔티티
일대다 양방향 회원 엔티티

  • 다대일 쪽은 insertable = false, updatable = false로 설정해서 읽기만 가능하게 함

이 방법은 일대다 양방향 매핑이라기보다는 일대다 단방향 매핑 반대편에 다대일 단방향 매핑을 읽기 전용으로 추가한 것뿐이다. 따라서 일대다 단방향 매핑이 가지는 단점을 그대로 가진다. 될 수 있으면 다대일 양방향 매핑을 사용하자.

 

3. 일대일 [1 : 1]

  • 1 : 1 은 그 반대도 1 : 1 관계
  • 1 : 1 관계는 주 테이블이나 대상 테이블 둘 중 어느 곳이나 외래 키를 가질 수 있다. 따라서 일대일 관계는 주 테이블이나 대상 테이블 중에 누가 외래 키를 가질지 선택해야 한다.

- 주 테이블 외래 키

외래 키를 객체 참조와 비슷하게 사용할 수 있어서 객체지향 개발자들이 선호

장점은 주 테이블이 외래 키를 가지고 있으므로 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.

 

- 대상 테이블 외래 키

전통적인 DB 개발자들은 이 방법을 선호

장점은 테이블 관계를 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지할 수 있다.

 

주 테이블에 외래 키

JPA는 주 테이블에 외래 키가 있으면 좀 더 편리하게 매핑할 수 있다.

 

- 단방향

일대일 주 테이블에 외래 키, 단방향

 

일대일 주 테이블에 외래 키, 단방향 예제 코드

이 관계는 다대일 단방향(@ManyToOne)과 거의 유사하다.

그 다음 반대 방향을 추가해서 양방향 관계로 만들어보자.

 

 - 양방향

일대일 주 테이블에 외래 키, 양방향
일대일 주 테이블에 외래 키, 양방향 예제 코드

 

대상 테이블에 외래 키

- 단방향

JPA에서는 대상 테이블에 외래 키가 있는 관계는 지원하지 않는다.

일대일 대상 테이블에 외래 키, 단방향

 

- 양방향

일대일 대상 테이블에 외래 키, 양방향
일대일 대상 테이블에 외래 키, 양방향 예제 코드

 

4. 다대다 [N : N]

정규화된 테이블 2개로 다대다 관계 표현할 수 없다. 그래서 중간에 연결 테이블을 추가한다.

N : M 다대다 연결 테이블

하지만 객체는 테이블과 다르게 객체 2개로 다대다 관계를 만들 수 있다.

@ManyToMany를 사용하면 편리하게 매핑할 수 있다.

클래스, 다대다 엔티티

 

다대다 : 단방향

다대다 단방향 회원
다대다 단방향 상품

여기서 중요한 점은 @ManyToMany와 @JoinTable을 사용하여 연결 테이블을 바로 매핑한 것이다. 

 

- @JoinTable 속성

  • @JoinTable.name : 연결 테이블을 지정
  • @JoinTable.joinColumns : 현재 방향인 회원과 매핑할 조인 컬럼 정보를 지정
  • @JoinTable.inverseJoinColumns : 반대 방향인 상품과 매핑할 조인 컬럼 정보를 지정

다대다 관계를 사용할 때는 연결 테이블을 신경 쓰지 않아도 된다.

 

- 저장

 

저장
저장 SQL

 

- 탐색

탐색
탐색 SQL

다대다 : 양방향

역방향 추가
연관관계 설정

양방향 연관관계는 연관관계 편의 메서드를 추가해서 관리하는 것이 편리

이렇게 하면

이렇게 간단히 연관관계 설정할 수 있다.

역방향 탐색

다대다 : 매핑의 한계와 극복, 연결 엔티티 사용

예를 들어 회원이 상품을 주문하면 연결 테이블에 단순히 주문한 회원 아이디, 상품 아이디만 담고 끝나지 않는다. 보통은 연결 테이블에 주문 수량 컬럼이나 주문한 날짜 같은 컬럼이 더 필요하다.

테이블, 연결 테이블에 필드 추가

이렇게 컬럼을 추가하면 더 이상 @ManyToMany를 사용할 수 없다. 왜냐하면 주문 엔티티나 상품 엔티티에는 추가한 컬럼들을 매핑할 수 없기 때문이다. 결국 연결 엔티티를 만들고 추가한 컬럼들을 매핑해야 한다.

클래스, 다대다를 푸는 연결 엔티티
회원 코드
상품 코드
회원상품 엔티티 코드

기본키를 매핑하는 @Id와 외래키를 매핑하는 @JoinColumn을 동시에 사용하여 기본키 + 외래 키를 한번에 매핑함

그리고 @IdClass를 통해 복합 기본키를 매핑했다. 

 

회원상품 식별자 클래스

 

- 복합 기본 키

회원 상품 엔티티 기본키는 MEMBER_ID, PRODUCT_ID 두개로 복합 기본키이다. 따라서 별도의 식별자 클래스를 만들어야 한다. 그리고 @IdClass를 사용하여 식별자 클래스를 지정하면 된다. 여기서는 MemberProductId 클래스를 식별자 클래스로 사용.

  • 복합 키는 별도의 식별자 클래스로 만들어야 함
  • Serializable을 구현
  • equals와 hashCode 메서드를 구현해야 함
  • 기본 생성자가 있어야 함
  • 식별자 클래스는 public
  • @IdClass를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있다.

- 식별 관계

부모 테이블의 기본 키를 받아서 자신의 기본 키 + 외래 키로 사용하는 것을 식별 관계라 한다.

회원상품은 회원의 기본키를 받아서 자신의 기본키 + 회원과의 관계를 위한 외래 키로 사용

또한 MemberProductId 식별자 클래스로 두 기본 키를 묶어서 복합 기본 키로 사용한다.

저장하는 코드
조회 코드

복합 키는 항상 식별자 클래스를 만들어야 한다. 복합 키를 사용하면 처리할 일이 많아진다.

  • 식별자 클래스 만들어야함
  • @IdClass 또는 @EmbeddedId도 사용해야 함
  • 식별자 클래스에 equals, hashCode도 구현

다대다 : 새로운 기본 키 사용

추천하는 방법은  DB에서 자동으로 생성해 주는 대리 키를 Long 값으로 사용하는 것이다.

 

- 장점

  • 간편하고 영구히 쓸 수 있다.
  • 비즈니스에 의존하지 않는다.
  • 복합 키를 만들지 않아도 되므로 간단히 매핑을 완성할 수 있다.

테이블, N : M 다대다 새로운 기본 키
주문 코드
회원 엔티티와 상품 엔티티 코드
저장 코드
조회 코드

 

다대다 연관관계 정리

  • 식별 관계 : 받아온 식별자를 기본 키 + 외래 키로 사용한다.
  • 비식별 관계 : 받아온 식별자는 외래 키로만 사용하고 새로운 식별자를 추가한다.

비식별 관계를 사용하는 것이 복합 키를 위한 식별자 클래스를 만들지 않아도 되므로 단순하고 편리하게 매핑할 수 있다.

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

프록시와 연관관계 관리  (0) 2023.07.15
고급 매핑  (0) 2023.07.14
연관관계매핑 기초  (0) 2023.07.13
엔티티 매핑  (0) 2023.07.11
영속성 관리  (0) 2023.07.10
profile

응애개발자

@Eungae-D

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!