JPA Entity 수정

10000DOO·2022년 12월 19일
1
post-thumbnail

JPA에는 entity를 수정하는 두 가지 방법이 있다.
✏️변경 감지(dirtyChecking)와 병합(merge) 이 두 가지 방법의 차이점에 대해 정리해 보려고 한다.

📌변경 감지(dirtyChecking)

변경 감지는 최초 엔티티가 1차 캐시에 들어온 상태와 현재 상태를 비교하여 변경된 부분이 있으면 반영하는 것이다.

// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);

transaction.commit(); // [트랜잭션] 커밋

동작 방식

  1. transaction.commit()을 하면 내부적으로 Flush()가 호출된다.
  2. 커밋 되는 시점에 엔티티와 스냅샷(최초로 1차 캐시에 들어온 상태)을 비교한다.
  3. 변경된 점이 있으면 update 쿼리를 생성한다.
  4. db에 쿼리를 반영하고 커밋이 이루어진다.

🚨주의점

엔티티 정보를 수정하고 entityManager.persist()를 하지 않는다.


📌병합(merge)

객체의 id값에 따라 새로 생성하거나 이미 존재하는 엔티티를 수정한다.

@PostMapping("/members/{memberId}/editName")
public String updateMemberName(@ModelAttribute("form") MemberNameEditForm form){
Member member = new Member();

member.setId(form.getId());
member.setName(form.getName());

em.merge(member);

return "redirect:/members";

동작방식

  1. merge()가 호출되면 해당 엔티티를 1차 캐시에서 조회한다.
  2. 1차 캐시에 존재하지 않는다면 식별자로 DB에서 검색해 나온 엔티티에 준영속 상태의 엔티티 값을 대입한다.
public void save(Member member){

  if(Member.getId() == null){
     em.persist(member);
  } 
  
  else{ 
     em.merge(member);
  }
}

위의 코드와 같이 id값 여부에 따라 persist()와 merge()를 나누어 사용한다.

🚨주의점

  1. 준영속 상태의 엔티티를 영속성 컨텍스트에 넣는 것이 아니라 준영속 상태의 엔티티와 동일한 식별자를 가진 엔티티를 DB에서 가져와 값을 대입시키는 것이다.
    따라서 영속된 엔티티를 사용하고 싶다면 merge()의 리턴 값을 사용해야 된다.
  2. merge()는 변경 감지(dirtyChecking)와 달리 준영속 상태 엔티티의 모든 필드를 반영하기 때문에 변경하고자 하는 값만 세팅하고 merge 한다면 나머지 필드는 null로 채워지게 된다.

✏️결론

특별한 상황이 아니라면 되도록 변경 감지(dirtyChecking)을 사용하여 엔티티 값을 수정하는 것이 좋아 보인다.

📚참고 자료

https://www.blog.ecsimsw.com/entry/JPA-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%88%98%EC%A0%95-%EB%B3%80%EA%B2%BD-%EA%B0%90%EC%A7%80%EC%99%80-%EB%B3%91%ED%95%A9

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

profile
iOS 개발자 지망생 https://github.com/10000DOO

0개의 댓글