GitHub

https://github.com/Choidongjun0830

Spring

[JPA 기본편] 다양한 연관 관계 매핑

gogi masidda 2024. 6. 19. 15:47

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

  1. 다중성
    1. 다대일
    2. 일대다
    3. 일대일
    4. 다대다: 실무에서 쓰면 안됨. 
  2. 단방향, 양방향
    1. 테이블은 외래 키하나로 양쪽 조인 가능해서 방향이라는 개념이 없음
    2. 객체는 참조용 필드가 있는 쪽으로만 참조 가능. 한쪽만 하면 단방향, 양쪽이 서로 참조하면 양방향(단방향 두개) 
  3. 연관 관계의 주인: 외래 키를 관리하는 참조

다대일

  • 관계형 데이터베이스에서는 다(N)쪽에 항상 외래키가 들어가줘야 한다.
    • 1쪽에 외래키를 두면 여러개를 설정해야 하니까
  • 가장 많이 사용하는 연관 관계
  • 반대는 일대다

다대일 단방향

//멤버 -> 팀
    @ManyToOne //멤버 입장에서는 멤버가 N
    @JoinColumn(name = "TEAM_ID") //조인할 컬럼
    private Team team;

 

아래 코드처럼 다대일 양방향은 반대쪽에도 넣어주면 된다.

//팀 -> 멤버
    @OneToMany(mappedBy = "team") //멤버 클래스에 있는 team 필드와 연결되어 있다.
    private List<Member> members = new ArrayList<Member>();

일대다

  • 여기서는 1이 연관 관계의 주인 
  • 이 모델은 권장하지 않음. 실무에서 이 모델은 거의 가져가지 않음. => 다대일 양방향을 사용하자
  • ex) 팀에서는 멤버를 알고 싶은데, 멤버에서는 팀을 알고 싶지 않을 때
  • 관계형 데이터베이스에서는 무조건 다쪽에 외래키가 있어야함. => 객체와 테이블 간의 차이 때문에 반대편 테이블의 외래키를 관리하는 특이한 구조가 된다는 것이 단점. 그래서 추가로 Update SQL이 실행됨. 
  • @JoinColumn을 쓰지 않으면 중간 테이블을 하나 추가하게 됨.

 

//팀 -> 멤버
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Member> members = new ArrayList<Member>();

 

일대다의 양방향은 공식적으로 존재하지 않지만,

연관 관계의 주인이 아닌 다에서 @JoinColumn(insertable = false, updatable = false)로 읽기 전용으로 양방향처럼 사용할 수 있다. 

다대일 양방향을 사용하자.


일대일

  • 일대일 관계는 반대도 일대일
  • 주 테이블이나 대상 테이블 중에 외래키 선택 가능
    • 주 테이블에 외래키
    • 대상 테이블에 외래키 
  • 외래키에 데이터베이스 유니크 제약 조건을 추가해야 일대일 관계가 될 수 있다. 

주 테이블에 외래 키 단방향

주 테이블은 멤버, 대상 테이블은 라커

 

다대일 단방향(양방향) 매핑과 유사함. 

 

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

위와 같은 것은 불가능. 지원이 안되고 방법도 없다. 

 

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

라커에 있는 멤버를 연관관계 주인으로 잡아서 라커 테이블에 매핑하면 된다. 멤버는 읽기 전용으로 만든다. 

일대일 관계는 내 엔티티에 있는 외래키를 내가 직접 관리해야 한다. 

 

정리

  • 주테이블은 더 많이 액세스하는 테이블
  • 주 테이블에 외래키
    • 주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
    • 객체 지향 개발자 선호
    • JPA 매핑 편리
    • 장점: 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
    • 단점: 값이 없으면 외래 키에 null 허용
  • 대상 테이블에 외래키
    • 대상 테이블에 외래 키가 존재
    • 전통적인 데이터베이스 개발자 선호
    • 장점: 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
    • 단점: 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨. 

다대다

  • 관계형 데이터베이스는 테이블 2개로 다대다 관계를 표현할 수 없다. -> 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어야 한다. 
  • 객체는 컬렉션으로 객체 2개로 다대다 관계 가능. 
  •  
  • 실무에서 쓰면 안됨.
    • 연결 테이블이 단순히 연결만 하고 끝나지 않음.
    • 주문시간, 수량 같은 데이터가 들어올 수 있음. 
    • 그래서 아예 중간 테이블을 만들어서 한계를 극복할 수 있다. 
@Entity
public class MemberProduct {

    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;

    private int quantity;
    private double price;
}

<중간 테이블 MemberProduct>

 

//멤버 엔티티
...
@OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts = new ArrayList<>();
    ...
//프로덕트 엔티티
...
@OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProducts = new ArrayList<>();
    ...
728x90