작성
·
105
·
수정됨
0
em.flush();
em.clear();
System.out.println("============= START =============");
Member findMember = em.find(Member.class, member.getId());
// 1
// findMember.getHomeAddress().setCity("newCity");
// 2
Address oldAddress = findMember.getHomeAddress();
findMember.setHomeAddress(new Address("newCity", oldAddress.getStreet(), oldAddress.getZipcode()));
// 3
findMember.getFavoriteFoods().remove("치킨");
findMember.getFavoriteFoods().add("한식");
강의 코드와 동일하게, Member 엔티티는 임베디드 타입인 homeAddress와 값 타입 컬렉션인 favoriteFoods를 포함하며, 상술한 코드도 값 타입 컬렉션 강의에서 23:30 까지 설명해주신 것과 동일합니다.
1번 주석에서, 임베디드 타입인 homeAddress의 city 필드를 수정하기 위해 city의 setter를 이용하면, Member에서 참조하는 homeAddress의 참조값은 바뀌지 않기 때문에 변경 감지가 일어나지 않는다고 이해했습니다.
따라서 2번 주석에서 볼 수 있듯이, 새로운 객체를 만들어 참조값을 바꿔주어야 변경 감지가 일어나 올바른 update가 될 수 있다고 이해했습니다.
그러나 3번 주석에서의 값 타입 컬렉션 수정을 보면, 결국 Member 엔티티가 가리키는 참조값은 원본 favoriteFoods의 참조값과 다르지 않은데 DB에서는 update가 일어난 것을 확인했습니다. 어떠한 이유로 이런 결과가 나오게 되는지 궁금합니다.
추가) 1번 주석의 코드를 실행할 경우, "newCity"로 변경이 되는 것을 확인했습니다. 참조값이 바뀌지 않는 데도 변경 감지가 일어나는 건가요? 아니면 제가 이해를 잘못하고 있는 부분이 있는 건가요..?
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
Ash님, 질문해주신 내용은 JPA의 변경 감지와 관련된 중요한 사항입니다. 코드를 바탕으로 하나씩 살펴보겠습니다.
임베디드 타입 변경 감지: 1번 주석
에서 findMember.getHomeAddress().setCity("newCity");
처럼 기존 임베디드 타입의 필드 값을 변경할 경우, JPA는 해당 객체의 참조 자체가 변화하지 않아도 내부 값의 변경을 감지할 수 있습니다. 이는 JPA가 제공하는 엔티티의 변경 감지 기능 덕분인데요, 엔티티 매니저는 기존 상태를 스냅샷으로 저장하고 있다가 flush 시점에 변경된 필드가 있는지 비교하여 업데이트 쿼리를 생성합니다. 따라서, 참조값이 바뀌지 않아도 내부 필드의 내용이 바뀌면 이를 업데이트 합니다.
값 타입 컬렉션 변경 감지: 3번 주석
에서 하신 것처럼 favoriteFoods
컬렉션의 아이템을 추가하거나 제거하면, JPA는 컬렉션의 변경 사항을 감지하고 이를 데이터베이스에 반영합니다. 값 타입 컬렉션의 경우, 어떤 요소들이 추가되거나 제거되었는지 JPA가 자동으로 추적하고 있으므로, 전체 컬렉션의 변화를 감지합니다. 이 경우 JPA는 변경된 내용을 바탕으로 기존 데이터의 DELETE 및 새로운 데이터의 INSERT를 조합하여 처리합니다.
추가적으로, 원본과 상관없이 엔티티나 값 타입의 필드가 수정되었다면 JPA는 이를 추적하기 위해 플러시 시점에 업데이트를 실행합니다.
아래 링크를 통해 관련된 더 깊이 있는 정보를 확인하실 수 있습니다:
- 값 타입과 JPA 변경 감지
- 임베디드 타입과 값 타입 수정 및 관리
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.