인프런 커뮤니티 질문&답변

임현강님의 프로필 이미지
임현강

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

양방향 연관관계와 연관관계의 주인 2 - 주의점, 정리

주인이 아닌 관계에서 읽기 질문

작성

·

203

0

안녕하세요 강사님, 수강 중 궁금증이 생겨 질문을 남깁니다.

지금까지 설명해주신 연관관계 주인이 왜 존재해야 하는지, 또 어떤 식으로 주인을 설정해야 하는지는 모두 이해했습니다.

설명하신 내용 중에 아래와 같은 내용이 있었는데요.

"연관관계 주인이 아닌 관계로는 읽기 기능만 사용이 가능하다. 그 외의 모든 관리는 관계의 주인이 처리한다."

이와 관련하여 팀에 새로운 멤버를 추가하고 싶을 때 team.getMembers().add(member)를 하면 DB에 반영되지 않고, member.setTeam(team)을 해야만 제대로 반영되는 부분까지 이해했습니다.

그런데, member.setTeam(team)으로 멤버가 팀을 가지도록 하고, 트랜잭션 커밋까지 완료해 해당 내용이 DB에 정상적으로 반영이 되었다면..

그 이후에 따로 team.getMembers().add(member)를 하지 않아도 Team이 가지고있는 List<Member> members에서 방금 추가한 member를 조회할 수 있어야 하는 것이 맞지 않나요?


이를 확인하기 위해 아래와 같은 코드로 실습을 진행하였습니다.

try {
Team team = new Team();
team.setName("TeamA");
em.persist(team);

Member member = new Member();
member.setName("MemberA");
member.setTeam(team);
em.persist(member);

tx.commit();

Team findTeam = em.find(Team.class, member.getTeam().getId());
List<Member> members = findTeam.getMembers();
for(Member m : members) {
System.out.println("Name : " + m.getName());
}

}catch(Exception e) {
tx.rollback();
}finally {
em.close();
}

team을 생성하고 member를 생성하여 member에 team을 할당해줬습니다.

em.persist를 통해 해당 객체들을 영속상태로 만들었고 tx.commit으로 flush처리까지 해주었습니다.

하지만 Name : MemberA는 출력되지 않습니다.

물론 DB에는 정상적으로 저장되었더라도 메모리에는 저장되지 않았기 때문에 조회가 안 된다고 말씀하시기는 했지만..

이 코드의 경우에는 Team과 Member가 정상적으로 DB에 적용된 후에 em.find()를 통해 새롭게 받아온 Team으로 조회한 것인데.. 왜 제대로 조회되지 않는 것인지 모르겠습니다.

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

추가 질문 하나만 더 드리겠습니다.

관계의 주인이 아닌 List<Member> members는 읽기 전용으로만 사용하기 때문에 members.add(member)를 아무리 해도 DB에 영향을 끼치지는 않겠지만..

쓰기 권한이 없는 녀석에게 쓰기 메서드가(list.add()) 존재하는 것 자체만으로 어떠한 문제가 야기될 수도 있지는 않을지 궁금합니다. 

이 부분에 대해서도 함께 답변해주시면 감사하겠습니다.

답변 5

1

김영한님의 프로필 이미지
김영한
지식공유자

ㅎㅎ 테넷이네요. 감사합니다.

0

임현강님의 프로필 이미지
임현강
질문자

아이고 강사님; 질문을 올리고 나서 바로 두번째 질문을 작성하는 사이에 첫번째 답변이 달렸었네요. 그걸 못 보고 재질문을 드렸습니다 ㅠㅠ 

확실하게 이해했습니다. 감사합니다!

0

김영한님의 프로필 이미지
김영한
지식공유자

답변을 다시한번 자세히 읽어주시겠어요?

그리고 보충설명을 드리자면, commit을 하더라도 제가 JPA에 저장한 객체의 상태를 JPA가 변경하지는 않습니다. JPA가 강제로 반대 방향(컬렉션)에 값을 강제로 넣어주지는 않는다는 뜻입니다.

이런 문제 때문에 꼭 양방향 연관관계에서는 양쪽으로 연관관계를 설정해주셔야 합니다!

반면에 영속성 컨텍스트를 완전히 초기화 하게되면, JPA가 처음부터 객체를 읽고 생성하기 때문에 이 경우에는 반대 방향(컬렉션)에서도 값을 읽을 수 있도록 JPA가 도와줍니다.

감사합니다.

0

임현강님의 프로필 이미지
임현강
질문자

이럴수가.. 질문을 올리고 강의를 다시 트니까 바로 첫번째 질문에 대한 부분이 나오네요...

근데 저는 em.find로 찾은 team.members에서 조회했는데도 member가 안 나오는데.. 어디가 잘못된걸까요?;;

H2 콘솔에서 조회하면 잘 들어가 있긴 합니다만..ㅠㅠ


ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

차이점을 알았습니다. 강사님께선 em.flush, em.clear를 하고서 조회를 실시하셨더라구요.

왜 저처럼 commit을 수행하고 조회할 때는 제대로 조회가 안 되는 걸까요?

commit을 하면 flush도 수행이 된다고 배웠는데 말이죠 ㅠㅠ

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 현강님

첫 번째 질문은

em.flush(), em.clear() 까지 모두 호출한 다음에 영속성 컨텍스트를 깔끔하게 비우고

em.find()로 처음부터 엔티티를 다시 조회해보면 리스트에도 데이터가 모두 들어와있는 것을 확인할 수 있습니다.

-> 이부분을 꼭 테스트 해주세요.

이렇게 영속성 컨텍스트에 저장한 단계에서는 개발자가 직접 설정한 연관관계만 유효합니다. 이런 문제 때문에 양방향 연관관계의 경우 양쪽으로 값을 설정해주셔야 합니다.

두 번째 질문의 답은 방금 말씀드린 내용과 같습니다.

감사합니다.

임현강님의 프로필 이미지
임현강

작성한 질문수

질문하기