JPA 연관관계(단방향/양방향 , 다중성)
인프런에 영한님 강의를 듣고 정리해본 블로그 게시물입니다.
[Spring] JPA의 연관관계(단방향/양방향, 연관 관계의 주인)
JPA에서 가장 중요한 것 JPA에서 가장 중요한 것을 뽑자면, "객체"와 데이터베이스 테이블이 어떻게 매핑되는지를 이해하는 것" 이라고 생각합니다. 왜냐하면 JPA의 목적인 "객체 지향 프로그래밍
nosechild.tistory.com
저번 블로그 게시물에 단방향/양방향에 대해서 자세하게 설명하였고, 또 연관관계의 주인에 대해서 설명을 하였습니다.
이번 블로그 포스팅은 다중성에 대해서 자세하게 설명하도록 하겠습니다.
앞에 한 블로그 내용에 있는데 테이블은 외래 키 하나로 양쪽으로 조인이 가능하고 사실상 단방향, 양방향의 개념이라는 방향 개념이 없습니다.
객체는 참조용 필드가 있는 쪽으로만 참조 가능합니다. 한쪽만 참조하면 단방향이고 양쪽으로 서로 참조하면 양방향입니다.
다중성에서 관계가 3가지의 케이스가 있습니다.
- 다대일[N:1] , 일대다[1:N]
- 일대일[1:1]
- 다대다[N:M]
다대일[N:1] - 단방향

다대일[N:1]의 관계는 가장 많이 사용하는 연관관계이다. Member에 Team 객체의 변수를 두어서 @OneToMany로 연관을 맺어주는 관계입니다.
다대일 관계의 반대는 일대다 관계입니다.
다대일[N:1] - 양방향

다대일[N:1] 양방향 관계는 기존의 다대일[N:1] 단방향 관계에서 Team 엔티티에 List members 변수를 추가해 주고 @OneToMany로 연관관계를 맺어줍니다. 그러고나서 mappedBy 로 연관관계의 주인을 만들어줍니다. 외래 키가 있는 쪽이 연관관계의 주인입니다. 양쪽으로 서로 참조하도록 개발을 하는데 먼저 단방향 관계로 형성해 주고 필요시에 양방향으로 참조하도록 개발을 합니다.
일대다[1:N] - 단방향(권장 X)

일대다[1:N] - 단방향 관계에서는 외래키를 바뀔때마다 Member에 있는 TEAM_ID를 바꿔주어야합니다. 실행을 해서 저장을 해보면 쿼리가 insert문이 2개가 나가고, 뒤에 update문 쿼리로 Member에 TEAM_ID가 주입이 됩니다. 성능상의 단점이 발생을 합니다.
일대다[1:N] - 단방향 정리
일대다[1:N] - 단방향은 일대 다(1:N)에서 일이 연관관계의 주인입니다. 테이블의 일대 다 관계는 항상 다 쪽에 외래키가 있어야합니다. 객체와 테이블의 차이 때문에 발생하는 반대편 테이블 외래키를 관리하는 특이한 구조가 만들어집니다. 관계를 만들 시에는 @JoinColumn을 꼭 사용해주어야 합니다. 그렇지 않으면 조인 테이블 방식을 사용해서 만들어집니다.(중간에 테이블을 추가하는 형태).
일대다[1:N] - 단방향의 단점은 엔티티가 관리하는 외래 키가 다른 테이블에 있어야하고, 연관관계 관리를 위해 추가로 UPDATE SQL 쿼리를 발생을 실행시켜야 합니다.
일대 다 - 단방향 매핑보다는 다대일 양방향 매핑을 사용합시다.
일대다[1:N] - 양방향 (스프링에서 공식적으로 존재 X)

@JoinColumn(insertable=false, updatable=false) 을 사용해서 읽기 전용 필드를 만들어주고 양방향처럼 사용하는 방법입니다.
되도록이면 이것도 다대일 양방향을 사용합시다.
일대일[1:1] 관계
일대일[1:1] 관계는 그 반대쪽 테이블은 일대일 관계를 의미합니다. 주 테이블이나 대상 테이블 중에 외래 키를 둘 다 선택이 가능합니다(주 테이블에 외래키, 대상 테이블에 외래키). 외래 키에는 데이터베이스에 유니크 제약 조건이 추가됩니다.
일대일[1:1] 관계 : 주 테이블에 외래 키 단방향

이 관계는 앞에 보았던 다대일[N:1] - 단방향(@ManyToOne) 매핑과 유사합니다.
일대일[1:1] 관계 : 주 테이블에 외래 키 양방향

다대일[N:1] - 양방향 매핑처럼 외래 키가 있는 곳이 연관관계의 주인입니다. 반대편은 mappedBy 적용을 해서 주인을 정해줍니다. JPA 매핑에 있어서 편리합니다. 장점으로는 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인이 가능합니다.
반대로 단점으로는 값이 없으면 외래 키에 null을 허용을 합니다.
일대일[1:1] 관계 : 대상 테이블에 외래 키 양방향

일대일[1:1] 관계 : 대상 테이블에 외래 키 양방향에서는 대상 테이블에 외래 키가 존재하는 매핑입니다. 이 방법은 전통적으로 DBA(데이터베이스 관리자)가 선호하는 방법입니다.
장점으로는 주테이블과 대상 테이블을 일대일에서 일대 다 관계로 변경할 때 테이블 구조를 유지합니다.
단점으로는 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩이 됩니다.
다대다[N:M] (쓰면 안 됨)

관계형 데이터베이스는 정규화된 테이블이 2개로 다대다 관계로 표현할 수 없습니다. 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야 합니다.

반면 객체는 컬렉션을 사용해서 객체 2개로 다대다 관계가 가능합니다. @ManyToMany를 사용하고 @JoinTable로 연결 테이블을 지정해야 합니다. 다대다 매핑을 단방향, 양방향 둘 다 가능합니다.
다대다 매핑의 한계
실전에서는 중간테이블을 사용하는 게 단순하지가 않습니다.
N:M 관계는 1:N, N:1로 바꿔서 설정
@ManyToMany→@OneToMany, @ManyToOne
@ManyToMany는 제약이 있습니다. 필드 추가를 안 하고, 엔티티 테이블이 불일치합니다.
실무에서는 @ManyToMany를 사용하지 않습니다.