준영속상태의 엔티티를 변경할 때 변경감지와 merge()

2021. 1. 29. 14:24JPA/JPA

준영속 상태의 엔티티를 업데이트할때, 두 가지 방법이 존재한다.

여기서 준영속 상태의 엔티티란 예전에 영속성 상태가 되었고 DB에 저장되었던 식별자가 존재하는 엔티티이지만 현재 영속성 상태가 아닌 상태를 말한다.

 

변경감지

  • 변경감지는 flush 시점에 영속성 컨텍스트가 관리하는 엔티티의 변경 내용을 체크하여 알아서 SQL 쿼리 생성 및 DB에 전달하는 기능이다. 변경감지 프로세스에 대해 정리를 해보면..
  1. 엔티티가 영속 상태가 된다.(persist나 find하여 DB에서 가져오는 경우)
  2. 영속성 컨텍스트는 스냅샷을 찍어 초기 상태를 저장해둔다.
  3. 엔티티의 필드에 값이 변경된다.
  4. 그리고 flush()가 호출된다.(커밋 시점이나 강제 flush)
  5. 영속성 컨텍스트는 스냅샷의 상태와 현재 상태가 다른(변경된) 데이터를 찾아서 변경됐는지 확인한다.
  6. 변경된 데이터는 UPDATE SQL을 생성하여 쓰기지연 SQL 저장소에 쿼리를 저장한다.
  7. 만들어진 SQL들을 모아 DB로 전송하여 쿼리 수행하게 한다.
  • 준영속 엔티티는 이런 변경감지를 통해 엔티티를 업데이트 할 수 있다. 따라서 해당 엔티티가 준영속상태이고 식별자만 있는경우 식별자로 DB에서 먼저 find하여 영속 상태를 만든 후, 엔티티의 필드 상태를 변경해주면 된다.

merge()

EntityManager의 merge는 사실 변경감지와 똑같은 역할을 한다.

merge 메서드를 호출하면 내부에서 변경감지가 일어나 먼저 엔티티를 find하여 영속 상태로 만든 후 변경감지를 하게 된다. 그러나 이 두가지에는 한 가지 차이가 존재한다.

 

변경감지는 업데이트할 필드를 선택할 수 있고 merge는 모든 필드에 대해 업데이트를 진행한다는 것이다.

 

이 것은 merge의 엄청난 단점이다. 변경할 엔티티의 필드값이 세팅되지 않은 경우 null로 업데이트가 되는것이다. 따라서 merge는 클라이언트 쪽에서 엔티티의 모든 상태값을 알고 있어야하는 부담감이 생긴다.

 

결론은 실무에서는 merge()를 사용하지 말고 변경감지를 직접 진행하자.