DevKim

[JPA] 다양한 연관관계 매핑 - N:1/1:N/1:1/N:M 본문

JPA

[JPA] 다양한 연관관계 매핑 - N:1/1:N/1:1/N:M

on_doing 2021. 6. 21. 16:19
728x90

[ 연관관계 매핑시 고려사항 ]

1. 다중성

1-1. DB와 매핑하기 위함이므로, DB의 관점에서 다대일,일대다..등을 보고 매핑해주면된다.

@ManyToOne,@OneToMany..

 

2. 단방향,양방향

2-1. 테이블

- 테이블은 FK 하나로 양쪽 join 가능해서 사실 방향이라는 개념이 없다.

2-2. 객체

- 객체는 한쪽만 참조하면 단방향, 양쪽 서로 참조하면 양방향이지만, 사실 양방향도 단방향이 2개인 것 이다.

 

3. 연관관계의 주인

3-1. 주인을 왜,언제 설정해야하는가?

- 테이블은 FK 하나로 두 테이블이 연관관계를 맺을 수 있지만,

객체의 양방향은 참조가 2군데이므로 둘중에 FK를 관리할 곳을 지정해야한다.

 

3-2. 주인 설정

- 결론적으론 '다'의 위치에 있는 객체가 연관관계의 주인이 된다.

- 주인의 반대쪽은 단순 조회만 가능하다.


[ 다대일 N:1 ]

1. 단방향

 

단방향의 경우 Member만 Team을 참조하면 되므로, 단순히 Member 와 FK 값을 매핑을 걸어주면된다.

 

2. 양방향

사실 양방향은 단방향에 객체만 추가해주고, mappedby로 연관관계의 주인이 누구인지 추가해주면된다.

이때 '다'는 Member이므로 Member에 FK를 두고 매핑해주면 된다.

 

테이블은 단방향이든 양방향이든 영향을 받지 않는다.


[ 일대다 1:N ]

 

1.단방향

결론적으로 이야기하면, 일대다 단방향/양방향 매핑보다는 다대일 양방향 매핑을 사용하는 것이 좋다고한다.

 

일대다 단방향은 일(1)이 연관관계의 주인이된다. 하지만 테이블의 일대다 관계는 항상 '다'쪽에 외래키가 있으므로,

이렇게 되면 주인 객체가 반대편 테이블의 외래 키를 관리하는 특이한 구조가 된다.

Team에서 업데이트를 했는데, Member에서 업데이트 쿼리가 나가게되어서,

업데이트 쿼리가 한번 더 나간다는 손실도 있고, 이렇게 설계히면 운영이 힘들어진다고 한다.

 

2. 양방향

- 이런 매칭은 공식적으로 존재하지 않는다. 억지로는 만들 수 있으나 역시나 추천하지 않는다고하신다.

* 다대일 양방향을 사용하자!!*


[ 일대일 1:1 ]

 

1. 외래키

- 1:1 관계는 거꾸로도 1:1 관계이기 때문에, 어디에 넣든 상관은 없다고한다.

- 외래키에 데이터베이스 유니크 제약조건을 추가해야한다.

 

2. 단방향

 

2-1. 주 테이블에 외래키 (추천)

Member가 한개의 라커를 가질 수 있다고 할때,

Member에 아무래도 access를 더 많이 할테니, 멤버를 주 테이블이라고 할 수 있다.

 

*다대일 단방향 매핑과 유사*

 

2-2. 대상 테이블에 외래키

단방향 관계는 JPA에서 지원하지 않는다.

 

3. 양방향

 

3-1. 주 테이블에 외래키

(2-1)의 단방향에 Locker에서 Member 객체만 참조하도록  추가해주면 된다.

다대일과 유사하게, 외래키가 있는 곳이 연관관계의 주인이므로 반대쪽은 mappedBy를 적용해주면된다.

 

3-2. 대상 테이블에 외래키

FK가 LOCKER에 있으면 어쩔 수 없이 양방향으로 걸어줘야한다.

(trade off로 그냥 받아들이기..)


4. 정리

'주'테이블에 외래키를 두는 것은 주 객체가 대상 객체의 참조를 가지고 있는 것 처럼, 주 테이블에 외래 키를 두고 대상 테이블을 찾으므로 JPA 매핑이 편리하고, 객체지향스럽다. 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능하지만, 값이 없으면 외래키에 null 허용한다는 단점이 있다.

대상 테이블에 외래키를 두는 방법은 만약 중간에 비즈니스 로직이 바뀌어서, 주 테이블과 대상 테이블의 관계를 일대다 관계로 변경해야할 때, 테이블의 구조가 유지된다.

하지만 프록시 기능의 한계로 지연로딩을 설정해도 소용이없고 항상 즉시 로딩된다.(치명적인 단점)


[ 다대다 N:M ]

결론적으로 실무에선 중간 테이블을 이용해서 다대다 관계를 일대다,다대일로 풀어내야한다.

위에선, PK와 FK를 묶었고, 

 

위에선 PK를 하나로 두고, 다른 것들을 FK로 내려주었다.

 

PK를 ORDER_ID와 같이 비즈니스적으로 의미 없는 일관적인 GeneratedValue로 생성해서 1개로 두는 것과 PK와 FK를 묶어서 쓰는 것들 각각의 장단점이 있지만, PK와 FK를 묶어서 사용하면 따로 또 지정해줘야하는 것이 있고,

운영의 유연성 측면에서 PK는 Gener-로 1개 두는 것을 더 선호하신다고한다.

 

** 테이블의 N:M 관계는 중간 테이블을 이용해서 1:N,N:1로 풀어서 사용해야한다.

하지만 실전에선 중간 테이블이 단순하지 않다. **


[ 궁금증 해결 ]

 

사실 Member에서 Order를 넣는게 좋은 설계는 아니라고 하셨다.

주문이 필요하면 주문에서 시작하면되고, 특정 회원의 주문 내역을 보고 싶으면 주문안에 있는 FK로 찾는게 더 나은 설계이며, Member를 찾아서 거기에서 getOrder로 주문내역을 뿌리는건 잘못된 설계라고 하셨다.

 

회원으로 로그인해서 주문내역을 확인하고 싶은 경우, 양방향의 경우 Member.getOrders로 처리 가능하지만

단방향의 경우 em.find(Order.class,member.getId) 로 쿼리문을 한번 더 날려야하는데,, 왜 단방향으로 처리하는게 좋은거지..? 라는 의문을 가지고 있을 때쯤, 질문창에서 다른 분이 남겨주신 질문에 영한님이 해결해주셨다.!

김영한님의 답변

Member와 Order의 연관관계는 한번 끊어주는 것이 더 좋다고한다.

끊어주지 않으면 연관관계가 너무 복잡해지기 때문이다.

 

※ 가급적이면 설계는 단방향으로 모두 설계해놓고, 필요하면 객체를 추가해서 양방향을 추가하도록 하자! ※

 

 

참고 강의, 자료 출처

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔

www.inflearn.com

 

728x90
Comments