Backend/Spring

JPA Dirty Checking

DooDuZ 2024. 6. 10. 03:04

JPA는 엔티티의 상태 변화를 감지하여 변경된 내용이 있는 경우 Update SQL을 처리한다.

 

 

Service에서 특정 Entity를 가져오라고 하면 EntityManager는 DB에서 해당 값을 찾아 가져온 후 PersistenceContext에 Entity를 저장하고, 동시에 loadedState에 해당 Entity의 초기 상태를 저장한다.

 

주인장은 어리고 똑똑해지고 싶다

 

가져온 Entity의 값을 변경하게 되면 즉시 DB에 반영되는 게 아니라 persistenceContext 내부에 있는 entityInstance의 value가 바뀐다.

그러나 양심에 찔린다

만약 위 상태에서 다시 객체의 상태를 원래 값으로 업데이트한다면 트랜잭션이 commit 하더라도 update query는 실행되지 않는다. loadedState에 있는 값과 현재 entity Instance의 값이 동일하기 때문이다.

다시 entity의 값을 수정하더라도 DB에 즉시 적용되지 않고 Entity Instance의 값만 변경되지만, 이 상태에서 commit 하면 DB에 적용하기 위한 update query가 실행된다. Entity 변경마다 update가 일어나는 게 아니라, 트랜잭션이 종료될 때 초기 로드값과의 비교를 통해 query가 작성되고 실행된다.

query가 실행되는 모습

 

다만 이번에 테스트를 진행하면서 생긴 의문점이 하나 있다. 쓰기 지연 저장소에 대한 것인데, 비영속 상태인 객체가 persist 되거나 Managed상태인 객체에 수정/삭제가 일어나면 actionQueue에 어떤 쿼리가 실행될 것인지 저장되어야 한다. insert와 delete의 경우 queue에 정상적으로 명령이 추가되는 걸 확인했는데, update에서만 아무 값도 추가되지 않았다.

 

commit 전에 flush를 수동으로 호출하면 updates의 값이 null에서 ExecutableList로 변경되긴 하지만 여전히 size는 0으로 들어온다. 그렇더라도 update쿼리가 정상적으로 실행되긴 한다. 다만 insertions나 delete는 작업마다 size가 1씩 늘어나던 걸 생각하면 이상한 일이다.