[JPA] Hibernate 디버깅 (수정 과정)
이번에는 엔티티 수정과정을 디버깅해보자.
엔티티를 수정하면 jpa에서는 dirty checking을 하고 update쿼리를 생성해준다.
정확히는 flush과정을 디버깅한다.
수정 과정
@Test
@Transactional
fun `update order`() {
val order = Order(price = 1000)
orderJpaRepository.save(order)
order.price = 2000
orderJpaRepository.flush()
}
먼저, order가 저장되는 부분에서 알고 넘어갈 부분이 있다.
entitiy가 영속화되면 영속성 컨텍스트 내부에 entityEntryContext에 entityEntry가 저장된다.
이 entityEntry에는 loadState라는 것이 있다. 이 값은 엔티티가 등록되는 시점의 스냅샷을 가지고 있어 dirty check가 가능하다.
order.price = 2000을 실행한 결과 entityInstance.price = 2000이 됐지만 loadedState는 여전히 1000이다.
entityEntry관련 재밌는 부분은 readOnly라면 loadedState = null로 저장된다.
jpa를 사용하면서 @Transactional(readOnly=true)를 설정하면 flush가 발생하지않아 성능 향상에 도움이 된다는 게 알려져 있다.
readOnly=true로 설정되면 엔티티 스냅샷(loadedStatus)가 아예 저장되지 않는다.
아무튼, EntityEntry는 dirtyCheck에 중요한 녀석이다.
flush가 호출되면 DefaultFlushEventListener에 onFlush가 호출된다.
여기서 flushEverythingToExecutions은 더티 체킹 후 update 이벤트를 actionQueue에 넣어주는 역할을 하고
performExecutions은 큐에 있는 이벤트를 실행하는 역할(업데이트 쿼리를 실행)을 담당한다.
flushEverythingToExecutions는
flushEverythingToExecution하위 메서드를 타고 가다 보면 dirtyCheck메서드가 실행되는데 여기서 변경된 프로퍼티를 찾고 매개 변수로 넘어온 event에 dirtyCheck관련 프로퍼티를 set 한다.
그리고 update의 대상이라면 event의 actionQueue에 action을 추가한다.
flushEverythingToExecutions를 실행한 결과 actionQueue에 이벤트가 담긴 걸 확인할 수 있다.
이후 actionQueue의 action이 실행되어 업데이트 쿼리가 실행된다.
정리
하이버네이트의 수정은 다음과 같은 순서로 엔티티가 수정된다.
1. flush가 실행되면 DefaultFlushEventListener에 onFlush가 호출된다.
2. onFlush의 flushEverythingToExecutions는 더티 체킹 및 event actionQueue에 update action을 추가한다.
2. onFlush의 performExecutions는 event actionQueue에 있는 action을 실행한다(update쿼리가 실행된다)