작성
·
1.4K
5
안녕하세요, 언제나 질 좋은 강의 잘 듣고 있습니다.
JPA 영속성 컨텍스트에서 변경 감지가 일어나는 시점에 대해서 궁금한 점이 있습니다.
영한님께서 강의 10분 45초 즈음에, "트랜잭션이 커밋되는 시점에 JPA가 변경 감지를 실행한다." 라고 언급을 해주셨습니다.
제가 의문이 드는 지점은,
영속성 컨텍스트 안에서의 변경 감지
영속성 컨텍스트 flush
트랜잭션 커밋
이 3개가 발생하는 시점입니다.
flush가 발생하면, 영속성 컨텍스트의 쓰기 지연 sql 저장소의 쿼리문들이 비워지고, db에 전송된다. 이 때 1차 캐시는 비워지지 않고, 트랜잭션이 커밋되는 시점에서 db에 전송된 쿼리문들이 커밋됨과 동시에 1차 캐시의 스냅샷과 현재 엔티티 상태와의 변경 감지가 일어난다.
---> 이것이 현재 제가 기본적으로 알고 있는 지식입니다.
제 질문은 다음과 같습니다.
그런데, 변경 감지라는 것이 결국 update 쿼리문을 날리기 위함인데, 저는 flush 이전에 변경 감지가 발생하여 쓰기 지연 sql 저장소에 update 쿼리문이 저장되는 것이 순서에 맞지 않나? 라는 생각이 듭니다.
또한 커밋되는 순간 변경 감지가 일어난다면, 트랜잭션 종료 바로 직전에 update 쿼리문이 날라가는 것이 맞을까요? 즉, (커밋으로 인한 flush가 아닌) 임의의 flush 호출 상황에서는 변경 감지로 인한 쿼리문이 전송되지 않는 것인가요?
질문 이외에도, 제 이해에 틀린 점이 있다면 알려주시면 감사하겠습니다!
답변 1
2
안녕하세요. 최재혁님, 공식 서포터즈 y2gcoder입니다.
먼저 좋은 질문 주셔서 감사합니다.
결국 변경 감지가 flush 이전에 발생해야 하지 않나 라고 질문주셨습니다.
먼저 아시는 내용부터 정리하고 가겠습니다.
트랜잭션을 커밋하겠다고 로직에서 요청을 보내면 먼저 flush()가 호출됩니다.
그때 엔티티와 스냅샷을 비교해서 UPDATE SQL을 생성하여 쓰기 지연 SQL 저장소에 저장합니다.
그 후, 쓰기 지연 SQL 저장소에 있는 쿼리를 Database에 보내고,
데이터베이스 트랜잭션을 커밋합니다.
먼저 flush는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영(영한님의 JPA 책, 107쪽)하는 것입니다. 저는 이 flush가 결국 변경 내역을 체크하라는 일종의 신호라고 이해했습니다. 사실 영속성 컨텍스트가 용빼는 재주가 있는 것이 아니라, 변경 감지를 언제 해야하는 지 자체적으로 체크하기는 효율적인 측면에서 어렵다고 생각합니다. dirty checking이라는 영어 표현과 같이, flush라는 신호를 받고 나서 영속성 컨텍스트가 스냅샷과 엔티티의 비교를 시작하는게 효율적이지 않나 개인적으로 생각해봤습니다.
네 맞습니다. SQL은 결국 트랜잭션 커밋하기 전에 DB로 날아갑니다.
감사합니다.
안녕하세요, y2gcoder님!
제가 나름대로 찾아본 자료(Baeldung 사이트)에서, 다음과 같은 설명이 있었습니다.
물론 이것도 공식 문서는 아니라서, 정답인지는 모르겠지만..
Persistence context keeps track of any changes made into a managed entity. If anything changes during a transaction, then the entity is marked as dirty. When the transaction completes, these changes are flushed into persistent storage.
영속된 엔티티에 대하여 변경 사항이 발생할 때마다 계속 체크하고 있다가, 트랜잭션이 완료될 때 DB에 flush가 된다고 하네요.
결론부터 말씀드리자면 저는 틀린 말이라고 생각합니다..
위와 다르게, 영한님의 JPA 기본편 강의에서는
flush()가 발생
영속성 컨텍스트의 1차 캐시를 뒤짐
스냅샷과의 비교(변경 감지)
DB에 쿼리 update 쿼리 날림
이라고 말씀을 해주셨네요. 책에서 언급하신 것처럼요!
저는 y2gcoder님께서 말씀해주신 것처럼, 영속성 컨텍스트 입장에서 변경 감지를 계속 추적하려면 어떤 알고리즘인지는 모르겠지만 효율적인 측면에서 힘들지 않을까 싶어서, 영한님의 말씀이 맞다고 생각하고 있습니다. 굳이 flush 상황이 아니면 dirty가 발생할 때마다 변경 사항을 추적한다고 하더라도, 어차피 update 쿼리는 엔티티의 최종적인 상태(일반적으로는 커밋 시 호출되는 flush 상황의 엔티티)를 기준으로 날릴 것이기 때문에 또 굳이 "Persistence context keeps track of any changes made into a managed entity" 할 이유가 있나 싶습니다.
좀 지엽적인 고민같기는 하지만 최근 면접에서 제대로 답하지 못했던 내용이라 자꾸 마음이 쓰이네요..
그래도 친절하게 답변 달아 주셔서 감사합니다. 저도 제 생각을 공유 드리고 싶어서 댓글 남깁니다!
올려주신 답글과 링크 모두 잘 읽어보았습니다.
먼저 생각을 공유할 기회를 주셔서 정말 감사합니다.
저도 저 글을 보고나니 JPA가 그렇게까지 할 수 있다고? 라는 생각이 들어서 좀 더 찾아보다가 발견한 문서를 공유드리고자 합니다.
By default Hibernate checks all managed entity properties. Every time an entity is loaded, Hibernate makes an additional copy of all entity property values. At flush time, every managed entity property is matched against the loading-time snapshot value:
https://vladmihalcea.com/the-anatomy-of-hibernate-dirty-checking/
해당 아티클의 일부를 발췌해온 것입니다. 보면 하이버네이트의 Dirty Checking 전략에 대해 소개하면서 도표의 시작 시점을 flush 부터 잡고 있는 것을 볼 수 있습니다. 실제로 엔티티가 조회 될 때마다 그 시점의 엔티티의 모든 속성 값을 스냅샷에 저장해놓고, flush 했을 때 snapshot의 내용과 영속 상태의 엔티티의 속성값을 비교한다고 말하는데, 또 baeldung(저도 많이 봅니다.) 에서는 저렇게 말을 하고 있으니 좀 찝찝하긴 합니다.
아무튼 좋은 정보, 생각 공유해주셔서 감사합니다 :)
면접 파이팅하셔서 좋은 곳에 취직하시길 바랍니다 :)
자료 공유 감사합니다. 잘 읽어보았습니다.
올려 주신 설명에서는 또 Baeldung과 다르게 설명하고 있네요. 그런데 메서드 명까지 적어 놓은 것 보니 좀 더 신뢰가 가는..ㅋㅋㅋ
아무튼 이렇게 생각과 정보를 공유해주셔서 정말 감사합니다. 기술이란 것은 정말 하나하나 배워갈수록 더 깊이를 요구하게 되는 것 같습니다.
응원 정말 감사합니다!! 꼭 좋은 결과 내겠습니다!!
제가 확인을 늦게 했네요..
정말 친절한 답변 주셔서 감사드립니다. 잘 읽어보았습니다.
이 부분 말씀 덕분에 깊게 이해되는 것 같습니다. 영한님께서 여러 번 말씀하시던 "용 빼는 재주가 없다." 그렇기 때문에 flush로 변경 감지 신호를 받는다. 가 맞는 논리의 순서인 것 같습니다.
또한 매번 변경 감지를 실행하면 롤백의 위험도 있고, 메모리 사용 면에서도 효율적이지 않을 것 같습니다.
감사합니다!