Develop/TIL(Today I Learned)

JPA - 엔티티 수정(merge, dirty check)에 대한 내용 정리

IJY 2023. 2. 15. 19:18

JPA(Java Persistence API -> Jakarta Persistence API)를 사용할 때 엔티티를 수정해야 할 때 아래처럼 2가지 방법이 있다.

  • 병합(merge)
  • 변경 감지(Drity checking)

아주 간단하게 정리하자면 "병합"은 수동, "변경 감지"는 자동이라고도 볼 수 있다.

사실 두 방법에 대한 중요한 차이점은 직접 명시하니 자동으로 해주니가 아닌 "어떻게 동작하는가?"라고 볼 수 있다.

일단 병합을 사용한 엔티티 수정에 대해 정리해보자

 

병합(merge)

병합의 경우 수정된 엔티티를 직접 merge() 메서드를 통해 반영시킨다.

이 때 엔티티의 모든 속성을 갱신하게 되기 때문에 비어있는 속성이 있는 경우 Null이 DB에 반영 될 수 있다.

병합을 사용해야 하는 경우는 준영속 엔티티인 경우라고 볼 수 있다.

준영속 엔티티란 영속 엔티티가 영속성 컨텍스트의 관리에서 벗어난 엔티티를 의미한다.

(비영속 엔티티와 준영속 엔티티의 차이점이 궁금하다면 접은글을 참고하세요)

더보기

비영속 엔티티와 준영속 엔티티의 차이가 헷갈릴 수 있는데, 확실한 차이점은 식별자의 존재 유무이다.

비영속 엔티티의 경우 식별자가 있는지 없는지 알 수 없는 상태 (파블로프의 식별자)

준영속 엔티티의 경우 식별자가 확실하게 있는 상태

즉, 영속석 컨텍스트의 관리를 벗어난 준영속 엔티티의 수정을 영속성 컨텍스트에 알려주기 위해 병합을 한다고 보면 된다.

(그런데 모든 속성 갱신이라는 동작을 보고 있으면 overlay가 아닌지..?)

 

변경 감지(Dirty checking)

변경 감지의 경우 트랜잭션 내에서 영속 엔티티의 수정이 발생하는 경우, 트랜잭션이 종료되는 시점에 수정된 내용을 영속선 컨텍스트에 반영하는 동작이다.

즉, 수정된 속성만 변경이 되기 때문에 병합처럼 의도치 않게 Null이 들어가거나 하지 않는다.

그럼 변경 감지만을 사용하면 되는 거 아닌가? 라는 생각이 자연스레 떠오를 것 같은데.. 그 생각이 맞다.

병합의 경우 정말 특별한 상황이 아니라면(이러한 경우도 회피하도록 구현하면 그만이긴 할 것 같은데..) 사용을 지양하고 전부 변경 감지를 이용하도록 구현하는게 좋다.


추가로 JPA에서 EntityManager를 사용하여 직접 meger()를 호출하는 것 말고 Spring Data JPA의 JpaRepository를 상속받아서 사용할 때 save() 메서드의 내부에도 merge() 메서드를 사용하는 경우가 있다.
이때는 save() 메서드에 들어온 엔티티의 식별자가 비어있는 게 아니라면(식별자가 객체라면 null, 기본 타입이라면 0인 경우를 비어있다고 판단) persist() 메서드가 아닌 merge() 메서드를 호출하여 동작하므로 영속 엔티티를 수정하는 경우라면 save() 메서드를 사용하지 말고 변경 감지로 수정 되도록 하는 것이 좋다.

 

오늘 공부를 하면서 병합과 변경 감지에 대해 알게 되어서 잊기 전에 기록을 해두려고 작성한 글이기 때문에 간략하게 정리를 해두었습니다.

더 자세한 내용은 나중에 다시 정리하도록 하겠습니다.