[JPA] 6. 다양한 연관관계 매핑

지니🧸·2023년 2월 13일
0

Spring Boot & JPA

목록 보기
13/35
post-thumbnail

본 문서는 인프런의 자바 ORM 표준 JPA 프로그래밍 - 기본편 (김영한) 강의를 공부하며 작성한 개인 노트입니다.

연관관계 매핑시 고려사항 3가지

  • 다중성 (예) 다대일, 일대다, 일대일, 다대다
  • 단방향/양방향
    • 테이블
      • 외래키 하나로 양쪽 조인 가능
      • 방향이라는 개념 X
    • 객체
      • 참조용 필드가 있는 쪽으로만 참조 가능
      • 한쪽만 참조 > 단방향
      • 양쪽이 참조 > 양방향
  • 연관관계의 주인
    • 테이블: 외래 키 하나로 두 테이블이 연관관계 맺음
    • 객체: A > B와 B > A 해서 참조가 2곳
      • 둘 중 테이블의 외래키를 관리할 곳은? 연관관계의 주인
      • 주인의 반대편 - 단순 조회만 가능. 외래 키 관리 X

🦀 다대일 (N:1), @ManyToOne

  • 연관관계의 주인 반대편에서 참조를 추가한다고 해서 테이블에 변화는 없음
  • 외래키가 있는 쪽이 연관관계의 주인이다

🦐 일대다 (1:N), @OneToMany

일에서 다를 관리 (ex) 팀에서 멤버를 관리 > Team 클래스에 List<Member> members 필드

  • 다 쪽에 외래키가 있음
  • 객체와 테이플의 차이 > 일에서 반대편 테이블의 외래키를 관리하게 됨 > UPDATE 쿼리 추가적으로 생성
  • @JoinColumn은 필수
    • 없이는 조인 테이블 방식 사용 > 테이블 추가 > 성능/관리 애매함
public class Team {
	...
  	@OneToMany
  	@JoinColumn(name = "TEAM_ID")
  	private List<Member> members = new ArrayList<>();
  	...
}
  • MEMBER 테이블의 TEAM_ID (FK, 외래키)를 같이 업데이트하기 위해 update 쿼리가 나가야 하기 때문에 성능상 문제
  • 테이블이 많아질 수록 관리가 어렵기 때문에 권장 X
    • Member에 주인권한을 주는게 더 좋음 > 다대일 단방향 + 양방향 조합이 더 좋음

일대다 양방향

  • 공식적으로 존재하지는 않음
  • @JoinColumn(insertable=false, updatable=false)
  • 읽기 전용 모드로 양방향처럼 사용
  • 다대일 양방향 사용하자

🦑 일대일 (1:1), @OneToOne

  • 주/대상 테이블 중에 외래키 선택 가능
  • 외래키가 있는 곳이 연관관계의 주인 & 반대편은 mappedBy 적용
  • 외래 키에 디비 유니크(UNIQUE/UNI) 제약조건 추가
  • @OneToOne
  • @JoinColumn(name = "")은 권장

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

Member가 주테이블인데 외래키는 Locker에 있을 경우
불가능함

대상 테이블에 외래키 양방향

가능은 함

주 테이블에 외래키 단방향

Member에 외래키가 있는게 성능상 유리함

  • Member 테이블을 자주 select한다고 봤을 때 locker_id가 여기 있는 것이 수월함
  • 하지만 Member 테이블에 null 값이 들어올 수 있어서 불편할 수는 있음
    선호되는 방식

주 테이블에 외래키 양방향

정리

  • 주 테이블에 외래 키
    • 주 테이블에 외래키를 두고 대상 테이블을 찾음
    • 객체지향
    • JPA 매핑 관리
    • 장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
    • 단점: 값이 없으면 외래키에 null 값
  • 대상 테이블에 외래 키
    • 대상 테이블에 외래 키
    • 디비
    • 장점: 주 & 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
    • 단점: 자연 로딩으로 설정해도 항상 즉시 로딩됨

🐡 다대다 (N:M), @ManyToMany

실무에서 사용 X

  • 관계형 디비는 정규환 테이블 2개로 다대다를 표현할 수 없음
    • 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야함
  • 객체는 컬렉션으로 객체 2개의 다대다 관계 가능
  • 한계
    • 실무에서 사용 불가
    • 연결 테이블은 연결에서 끝나지 않음
    • 다양한 데이터가 들어올 수도 있는데 중간테이블에는 정보 추가가 안됨
    • 쿼리가 복잡해짐
  • 해결
    • 연결 테이블용 엔티티 추가 > 연결테이블을 엔티티로 승격
    • @ManyToMany > @ManyToOne + @OneToMany
    • 정 필요하면 제약조건 추가

🐙 실전 예제 3 - 다양한 연관관계 매핑

  • 엔티티 배송 & 카테고리 추가
    • 주문:배송 = 1:1
    • 상품:카테고리 = N:M
    • Delivery (+ DeliveryStatus enum) & Category 클래스 생성

@JoinColumn

외래 키 매핑시 사용
속성

  • name - 매핑할 외래키 이름
    • 기본값: 필드명 + _ + 참조하는 테이블의 기본키 컬럼명
  • referencedColumnName - 외래키가 참조하는 대상 테이블의 컬럼명
    • 기본ㄱ밧: 참조하는 테이블의 기본키 컬럼명
  • foreignKey (DDL) - 외래키 제약조건을 직접 지정
    • 테이블 생성시만 사용
  • unique, nullable, insertable, updatable, columnDefinition, table - @Column 속성과 같음

@ManyToOne

다대일 관계 매핑
속성

  • optional - false로 설정하면 연관된 엔티티가 항상 있어야함
    • 기본값: True
  • fetch - 글로벌 패치 전략 설정
    • 기본값
      • @ManyToOne=FetchType.EAGER
      • @OneToMany=FetchType.LAZY
  • cascade - 영속성 전이 기능 사용
  • targetEntity - 연관된 엔티티의 타입 정보 설정
    • 거의 사용X
    • 컬렉션을 사용해도 제네릭으로 타입 정보 알 수 있음

@OneToMany

다대일 관계 매핑
속성

  • mappedBy - 연관관계의 주인 필드 선택
  • fetch - 글로벌 패치 전략 설정
    • @ManyToOne=FetchType.EAGER
    • @OneToMany=FetchType.LAZY
  • cascade - 영속 전이 기능 사용
  • targetEntity - 연관된 엔티티의 타입 정보 설정
    • 거의 사용 X
    • 컬렉션을 사용해도 제네릭으로 타입 정보 알 수 있음
profile
우당탕탕

0개의 댓글