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

임현강님의 프로필 이미지

작성한 질문수

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

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

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

21.02.21 18:08 작성

·

199

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

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

2021. 02. 21. 23:31

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

0

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

2021. 02. 21. 19:10

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

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

0

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

2021. 02. 21. 18:49

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

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

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

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

감사합니다.

0

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

2021. 02. 21. 18:21

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

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

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


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

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

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

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

0

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

2021. 02. 21. 18:20

안녕하세요. 현강님

첫 번째 질문은

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

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

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

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

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

감사합니다.