강의

멘토링

로드맵

Inflearn brand logo image

인프런 커뮤니티 질문&답변

천다인님의 프로필 이미지
천다인

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

플러시

영속성 컨텍스트 스냅샷 갱신 시점

작성

·

136

1

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.

1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)

질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)

[질문 내용]
flush()를 할 때 영속성 컨텍스트 스냅샷이 갱신되는 지 확인받고 싶습니다. 다른 질문에서 해당 내용을 찾지 못했고, Baeldung과 같은 사이트, 또는 다른 블로그 글들에서 이와 같은 내용을 확인할 수 있는 곳이 없어 ChatGPT를 통해 확인했지만, 여전히 확신이 서는 곳에서 답변을 받은 것이 아니기에 질문 남겼습니다.

다음과 같은 코드를 실행할 때,

EntityTransaction tx = em.getTransaction();
tx.begin();

// id는 1L, name은 AAA인 Member 엔티티
Member memberA = new Member(1L, "AAA");
em.persist(memberA);
em.flush();
memberA.setName("NOTA");

tx.commit();

flush를 직접 호출하는 시점은 영속성 컨텍스트에는 memberA에 대한 엔티티는 있지만 스냅샷은 없는 상태로, flush()가 수행되면서 데이터베이스와의 동기화를 위해 INSERT 쿼리문이 날라갑니다.

제가 생각하기에는 이 때(첫번째 flush()), memberA에 대한 스냅샷이 생성되어야 memberA.setName()을 수행하면서 변경감지를 통해 비교할 대상인 스냅샷이 존재할 수 있다고 생각합니다.

그렇기에 commit()을 호출할 때, flush()가 자동으로 호출되면서 비교할 스냅샷을 통해 UPDATE 쿼리문을 생성할 수 있다고 생각했습니다.

이를 통해 제가 확인하고 싶은 것은 다음 2가지인데, 맞는지 확인 부탁드립니다.

  1. flush() 호출 시 영속성 컨텍스트에서 스냅샷이 갱신된다.

  2. persist() 시에는 스냅샷이 생성되지 않는다.

관련 자료를 확인하고 싶은데 혹시 이를 확인할 수 있는 자료가 있다면 알려주시면 감사하겠습니다.

강의 잘 보고 있습니다!

답변 1

0

안녕하세요, 인프런 AI 인턴입니다. 천다인님.

질문해주신 영속성 컨텍스트와 스냅샷 갱신 시점에 대해서 알아보겠습니다. 영속성 컨텍스트는 JPA에서 엔티티의 상태 변화를 관리하는 중요한 역할을 하는데요, 이에 관련된 몇 가지 궁금증을 해결할 수 있는 자료를 준비했습니다.

  1. flush() 호출 시 영속성 컨텍스트에서 스냅샷이 갱신된다: flush()는 영속성 컨텍스트에서 변경된 엔티티들을 데이터베이스와 동기화하는 작업을 수행합니다. 이때, 스냅샷은 축적된 변경 사항과 비교하여 UPDATE 쿼리를 생성하는 데 사용될 수 있습니다. 다만, flush() 자체가 모든 메모리를 갱신하는 것은 아니고, 기존 내용과의 비교를 통한 변경 사항을 특정 위치에 기록하는 역할을 합니다.

  2. persist() 시에는 스냅샷이 생성되지 않는다: persist()는 엔티티를 영속성 컨텍스트에 등록하여 관리를 시작하는 것이며, 이 시점에서는 초기값이 데이터베이스에 기록되지 않고, insert 쿼리를 위한 준비에 들어갑니다. 실제로 스냅샷은 데이터베이스와의 싱크 작업을 확인하는 시점, 즉 flush 시점 또는 트랜잭션 커밋 시점에서 유의미하게 사용됩니다.

관련한 더 구체적인 설명은 다음 링크에서도 확인하실 수 있습니다:

위 질문들에서는 스냅샷과 변경 감지의 작동 방식, flush와 관련된 여러 시나리오에 대해 더 깊이있는 답변을 제공하고 있습니다. 해당 답변을 보시면 더욱 명확한 이해가 가능하시리라 생각합니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

천다인님의 프로필 이미지
천다인
질문자

답변 링크가 조금 애매한 것 같은데, flush()를 통한 변경감지 후 UPDATE문을 저장하고, 스냅샷도 갱신된다는 것 맞나요?

그리고 persist() 시에는 스냅샷이 생성되지 않는 것이 맞을까요?

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 천다인님

생각하신 것 처럼 하이버네이트의 경우 persist()는 flush() 이후에 스냅샷이 생성된다고 보시면 됩니다.

왜냐하면 DB와 동기화되지 않은 상태이므로, JPA 구현체 입장에서는 “변경 감지용 스냅샷”을 만들 실익이 없습니다. (DB에 없는 ‘신규’ 엔티티이므로 변경이라고 해봤자 다 새 값이기 때문입니다.)

감사합니다.

천다인님의 프로필 이미지
천다인
질문자

강사님, 답변 감사합니다!

저 질문이 하나 더 있는데,

Member member = new Member(1L, "member");
em.persist(member);
member.setName("Test");
tx.commit();

위 코드를 실행하면 아래와 같이 SQL 쿼리문이 로그에 찍히는데요

Hibernate: 
    /* insert for
        hellojpa.Member */
insert 
    into
        Member (name, id) 
    values
        (?, ?)
Hibernate: 
    /* update
        for hellojpa.Member */
update Member 
    set
        name=? 
    where
        id=?

persist()를 할 때 member 객체를 영속성 컨텍스트에 등록하고, 해당 상태에서는 신규 엔티티이므로 setName()으로 이름을 바꾸더라도 새로운 값이고, DB와 동기화되지 않았기에 스냅샷도 없을 것이라 생각했습니다.

그래서 쿼리문도 INSERT 쿼리문 1개만 발생할 줄 알았는데, 왜 UPDATE 쿼리문도 함께 발생하는지 알려주실 수 있을까요?

정확히는 persist를 수행하고 setName을 수행할 때, 스냅샷이 생성되지 않은, 스냅샷이 없는 상태에서 어떻게 변경을 감지하여 UPDATE 쿼리문을 작성한 것인지 궁금합니다.

감사합니다!

천다인님의 프로필 이미지
천다인

작성한 질문수

질문하기