EntityManager에는 Merge() 함수와 Persist()함수가 있다.
Merge와 Persist의 차이는 무엇일까?
한마디로 얘기하자면 Merge는 Detached 상태의 Entity를 다시 영속화 하는데 사용되고
Persist는 최초 생성된 Entity를 영속화 하는데 사용된다.
그렇다면 Detached 상태란 무엇일까? Detached 상태는 한번이라도 영속화 되었지만 현재는 영속화 되지 않은 상태인 Entity를 의미한다.
어떠한 경우에 Detached상태인 Entity가 생기는지 확인해보자.
다음 코드를 함께 보자.
Popinfo mangedPopinfo = em.find(Popinfo.class, "-BnNUFqJWRw");
Popinfo updatePopinfo = new Popinfo();
updatePopinfo.setId(mangedPopinfo.getId());
updatePopinfo.setTitle("빙글뱅글");
Popinfo managedUpdatedPopinfoManaged = em.merge(updatePopinfo);
em.flush();
popinfoNew Entity가 먼저 영속화되었고 이와 동일한 Id를 가진 popinfoUpdate 엔티티가 생성 되었다.
Id가 동일한 Entity(popinfoNew )가 이미 영속화 되었을때 그 Entity와 동일한 ID를 가진 다른 Entity(popinfoUpdate )는 Detached Entity인 것이다 .
em.flush();를 실행하면 어떤 일이 발생할지 로그를 확인해보자.
Hibernate: select popinfo0.id as id1_2_0, popinfo0.artist as artist2_2_0, popinfo0.channel_title as channel_3_2_0, popinfo0.content_type as content_4_2_0, popinfo0.img as img5_2_0, popinfo0.link as link6_2_0, popinfo0.title as title7_2_0, popinfo0.upload_time as upload_t8_2_0 from popinfo popinfo0 where popinfo0.id=?
Hibernate: update popinfo set artist=?, channel_title=?, content_type=?, img=?, link=?, title=?, upload_time=? where id=?
업데이트 쿼리가 발생하게 된다.
그렇다면 merge후 반환된 Entity는 이전 Entity와 어떤 관계인지 확인해보자.
assertEquals(managedUpdatedPopinfoManaged, updatePopinfo);
이 결과는 false로 떨어질 것이다.
로그를 확인해보자.
former : com.tomato.springwebservice.domain.kpop.Popinfo@1d01fa0c
latter : com.tomato.springwebservice.domain.kpop.Popinfo@5b27d03d
managedUpdatedPopinfoManaged Entity는 영속화된 Entity를 참조하고 updatePopinfo는 그렇지 않다. 즉, 어떠한 Entity를 수정함에따라 Dirtycheck가 가능할 수도 있고 불가능할 수도 있다.
managedUpdatedPopinfoManaged를 수정하게되면 수정사항이 DB에 반영되게 될것이다. 하지만 updatePopinfo를 수정하면 수정사항이 DB에 반영되지 않는다.
테스트 코드를 조금 수정해서 비교해보자.
Popinfo managedPopinfo = em.find(Popinfo.class, "-BnNUFqJWRw");
Popinfo updatedPopinfo = new Popinfo();
updatedPopinfo .setId(managedPopinfo .getId());
updatedPopinfo .setTitle("빙글뱅글");
Popinfo managedUpdatedPopinfo = em.merge(updatedPopinfo);
em.flush();
managedUpdatedPopinfo.setTitle("짧은치마");
em.flush();
select popinfo0.id as id1_2_0, popinfo0.artist as artist2_2_0, popinfo0.channel_title as channel_3_2_0, popinfo0.content_type as content_4_2_0, popinfo0.img as img5_2_0, popinfo0.link as link6_2_0, popinfo0.title as title7_2_0, popinfo0.upload_time as upload_t8_2_0 from popinfo popinfo0 where popinfo0.id=?
Hibernate: update popinfo set artist=?, channel_title=?, content_type=?, img=?, link=?, title=?, upload_time=? where id=?
Hibernate: update popinfo set artist=?, channel_title=?, content_type=?, img=?, link=?, title=?, upload_time=? where id=?
두번의 Update가 발생한것을 확인할 수 있다.
Popinfo managedPopinfo = em.find(Popinfo.class, "-BnNUFqJWRw");
Popinfo updatedPopinfo = new Popinfo();
updatedPopinfo .setId(managedPopinfo .getId());
updatedPopinfo .setTitle("빙글뱅글");
Popinfo managedUpdatedPopinfo = em.merge(updatedPopinfo);
em.flush();
updatedPopinfo.setTitle("짧은치마");
em.flush();
Hibernate: select popinfo0.id as id1_2_0, popinfo0.artist as artist2_2_0, popinfo0.channel_title as channel_3_2_0, popinfo0.content_type as content_4_2_0, popinfo0.img as img5_2_0, popinfo0.link as link6_2_0, popinfo0.title as title7_2_0, popinfo0.upload_time as upload_t8_2_0 from popinfo popinfo0 where popinfo0.id=?
Hibernate: update popinfo set artist=?, channel_title=?, content_type=?, img=?, link=?, title=?, upload_time=? where id=?
반면에, 한번의 update만 발생하였다.
결론.
Merge : Detached Entity ⇒ Managed Entity
Persist : New Entity ⇒ Managed Entity
두가지를 명확하게 이해하고 사용하자.