DevKim

[JPA] 연관관계 매핑 - 단방향,양방향 연관관계 ,연관관계의 주인 본문

JPA

[JPA] 연관관계 매핑 - 단방향,양방향 연관관계 ,연관관계의 주인

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

01. [ 객체 설계를 테이블 설계에 맞춘 방식의 경우 ]

다음과 같이 연관관계 매핑을 하지않고, Member가 외래키 값을 그대로 들고 있는 경우엔

member에서 외래 키 식별자를 직접 다루게 된다. 

이렇게 되면, member를 저장할 때 다음과 같이 team에서 id를 받아와서, 그 id를 가지고 teamid를 설정해주어야한다.

이러한 방법은 전혀 객체지향스럽지 않고.. 바로 getTeam( )을 해야 속이 시원할 것 같은 느낌이다.

 

더불어, 조회시에도 이슈가 있다.

Team을 조회하기 위해선, member id로 원하는 member를 find하고,

찾은 member.getTeamId로 team의 id값 찾고..그 id값으로 다시 또 팀을 찾아줘야한다.

이렇게 되면 연관관계가 없으므로 계속 DB에 물어봐서 꺼내야한다.

전혀 객체지향스럽지 않은 방식이다.

 

즉,

객체를 테이블에 맞춰서 데이터 중심으로 모델링을 하면, 협력 공동체를 만들 수 없다.

(객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것이다. 라고 책에서 말했다..)

 

이때, '테이블' 과 '객체'의 연관관계의 차이를 이해하는 것이 가장 중요하다고한다.

1. 테이블은 외래키로 'JOIN'을 사용해서 연관된 테이블을 찾는다.

2. 객체는 '참조'를 이용해서 연관된 객체를 찾는다.


[ 02. 단방향 연관관계 ]

위에서의 모델링을 객체 연관관계를 이용해서 다시 모델링하면 다음과 같다.

여러명의 member가 team에 들어갈 수 있으니, member와 team은 다:1 관계이다.

따라서 Member에서 Team과의 관계가 어떤 관계인지 매핑해주고,

이 관계를 할 때 Join하는 컬럼은 테이블 연관관계에서의 외래키이기 때문에 TEAM_ID와 매핑해주었다.

이렇게 연관관계를 매핑해주면, 회원 저장시 member.setTeam(team) 으로만 넣어주면

JPA가 알아서 team에서 PK값 꺼내서 FK insert 할 때, FK로 사용을 한다고한다. 

조회시엔 get으로 바로 가져올 수 있고

수정시에도 member.setTeam(team)으로 수정 가능해진다.

 

실행해보면, select 쿼리가 안나가는데, 그건 영속성 컨텍스트의 1차 캐시에 저장되어 있는 것을 찾아서

반환했기 때문에 그렇다.

DB에서 가져오는 쿼리를 가져오고 싶으면,

em.flush( ) 후 em.clear( ) 를 해주어

플러쉬해주고 clear로 영속성 컨텍스트를 초기화해주면 된다.


[ 03. 양방향 연관관계 ]

 

단방향 연관관계와 양방향 연관관계에서의 테이블 연관관계는 변화가 없다.

왜?

Member에서 소속된 Team을 알고 싶거나, Team에서 소속한 Member을 알고 싶을 땐

양쪽의 TEAM_ID 두개를 join하면 되기 때문이다. 

FK하나로 양쪽을 다 알 수 있다.

 

하지만 객체의 연관관계는 그렇지 않기 때문에, 추가로 Team에도 member를 넣어줘야한다.

 

Team이 여기서는 연관관계 주인의 반대편이므로 mappedBy를 넣어주었다.

ArrayList로 초기화해둬야 나중에 add 할때 null point 안뜸

이제 서로서로 탐색 가능하다. 

그런데 이렇게 해서 출력하면 빈 리스트가 출력이 된다

왜?

아직 DB에 반영이 안되었기 때문이다.

이럴땐 강제로 플러쉬를 해주면 된다!


 

========================= 연관관계의 주인==========================

사실상, 객체의 연관관계는 서로 다른 단방향 2개가 있는 것이고

테이블은 연관관계가 1개가 있는 것이라고 한다.

 

그러므로, 둘 중 하나로 외래 키를 관리해야한다.

만약 팀에서의 멤버값이 변하고 멤버에서 팀의 값이 바뀐다면,

어느 값일 때 FK를 업데이트 해야하는지가 모호해진다.

 

** 양방향 매핑 규칙 **

1. 하나를 연관관계의 주인으로 지정하고, 주인만이 FK를 등록,수정할 수 있다.

2. 주인의 반대쪽은 조회만 가능하다.

-> 주인의 반대쪽에서 아무리 수정,등록해도 아무일도 일어나지 않음!

DB에 TEAM_ID =NULL으로 뜸

3. 주인은 외래키가 있는 곳을 주인으로!

( 다:1의 관계에서 다 쪽을 주인으로 두자)

 

=================================================

 

** 양방향 매핑시 가장 많이 하는 실수 **

 

1. 연관관계의 주인에 값을 입력하지 않는 경우가 많다고 하니 주의하자.

 

2. 무조건 항상 '양쪽' 다 값을 입력하는 것이 맞다고한다.

( test case 작성시,,플러쉬 안해준 순수 1차 캐시에서 값 읽어올때..등등의 상황을 위해..)

-> 연관관계 편의 메소드를 생성하자.

( 양쪽에 둘다 생성하면 오류날 수 있으니,

Member에서 team을 넣던지 team에서 member을 넣던지 하면됨 )

<1> Member에 Team을 반영한 경우

<2> Team에서 Member을 넣어준 경우

 

3. 양방향 매핑시 무한루프를 조심하자!

- lombok의 toString() 은 웬만하면 사용하지 않기

-JSON 생성 라이브러리 사용시,

Controller에서 Entity 자체를 절대 반환하지 않기!!

무조건 DTO로 변환해서 반환하기

 

------------------------------------------------------정리----------------------------------------------------

1) 설계시 일단 단방향 매핑으로 다 끝낸다고 생각하고, 단방향 매핑으로만 설계완료하기

2) Table 설계 후 객체 설계

3) 개발 단계로 들어간 후, 양방향이 필요하면 추가하해도됨

-----------------------------------------------------------------------------------------------------------------

 

그림 출처 : 자바 ORM 표준 JPA 프로그래밍

728x90
Comments