Database/SQL

[JPA] flush는 언제 일어날까?

pink_salt 2024. 12. 18. 11:33
728x90

Flush : 영속성 컨텍스트와 데이터베이스의 동기화

JPA Flush는 영속성 컨텍스트(Persistence Context)의 변경 내용을 DB에 반영하는 것을 말한다.

영속성 컨텍스트는 엔티티 객체를 관리하는 메모리 공간이다. Flush는 이 영속성 컨텍스트에서 변경된 엔티티를 데이터베이스와 동기화하는 데 사용된다.

즉, 영속성 컨텍스트 메모리 상에 저장된 객체 상태를 데이터베이스에 반영하는 것이다.
 
이 때, Flush는 동기화하는 것이기 때문에 Flush가 일어나도 1차 캐시된 영속성 컨텍스트는 그대로 유지된다.
( clear는 영속성 컨텍스트를 비워서 관리 중인 엔티티를 모두 제거하는 것이다. )
 

 

Flush가 발생하는 시점

Flush는 자동으로 발생할 수도, 수동으로 발생시킬 수도 있다.

일단 자동으로 발생하는 경우에 대해서 보겠다.

1. 트랜잭션 commit 시점

트랜잭션이 종료될 때 flush가 호출되어 영속성 컨텍스트에 있는 변경 내용을 데이터베이스에 반영한다.

@Transactional
public void saveEntity(Entity entity) {
    entityManager.persist(entity);
    // 트랜잭션이 commit될 때 flush 발생
}

 

 

2. JPQL 쿼리 실행 시점

JPQL은 영속성 컨텍스트의 상태와 일치해야 하므로 실행 전에 flush가 발생한다.

String jpql = "SELECT e FROM Entity e WHERE e.name = :name";
entityManager.createQuery(jpql).setParameter("name", "example").getResultList();
// JPQL 실행 전 flush 발생

 

3. Native Query 실행 시점

JPQL과 동일한 이유로 Native Query 실행 전에 flush가 발생한다.


다음으로 수동으로 flush를 발생시키는 것을 보겠다.

EntityManager.flush() 호출

수동으로 flush를 호출하여 영속성 컨텍스트를 데이터베이스와 동기화할 수 있다.

entityManager.persist(entity);
entityManager.flush(); // 수동 flush 호출

 

Flush 동작 과정

flush는 영속성 컨텍스트에 있는 변경된 엔티티 상태를 기반으로 SQL을 생성하고 데이터베이스에 반영하는 과정을 포함한다.

1. 엔티티 변경 사항 감지

 jpa는 영속성 컨텍스트에 관리 중인 엔티티를 검사하여 변경된 속성을 감지한다. 이 동작을 Dirty Checking 이라고 한다.

Entity entity = entityManager.find(Entity.class, 1L);
entity.setName("new name"); // Dirty Checking 발생

 

  • 이 시점에서 entity 객체의 name 필드 값이 변경됩니다.
  • 영속성 컨텍스트는 entity가 Dirty 상태임을 감지합니다.

 

2. SQL 생성

변경 사항에 따라 적절한 SQL 문(INSERT, UPDATE, DELETE)이 생성되어 영속성 컨텍스트에 기록된다.

  • SQL(UPDATE entity_table SET name = 'new name' WHERE id = 1)은 생성되지만 즉시 실행되지 않습니다.

 

3. SQL 실행 준비

SQL이 생성되지만, flush 단계에서는 즉시 실행되지 않을 수도 있다. 이 현상은 SQL 실행을 최대한 지연시켜 성능 최적화를 도모하는 JPA의 전략인 Write-behind이다.

Write-behind
변경된 엔티티에 대해 Dirty Checking이 발생하면 해당 변경 내용은 영속성 컨텍스트에 기록되고, SQL은 즉시 실행되지 않고 flush 시점까지 대기한다.
-> Dirty Checking으로 결정된 SQL 실행 계획을 "쓰기 지연"하여 최적화합니다.

실행은 트랜잭션 commit 시점에 이루어진다.

 

4. 데이터베이스 동기화

flush가 호출되면 SQL 문이 데이터베이스로 전송되어 변경 사항이 반영된다. 단, 트랜잭션이 롤백되면 반영된 내용이 취소된다.

 


면접 질문

Q. JPA의 flush란 무엇인가요? 언제 발생하나요?

더보기

flush는 JPA의 영속성 컨텍스트(Persistence Context)에서 관리하는 변경 사항을 데이터베이스에 동기화하는 작업입니다. 이를 통해 객체의 상태와 데이터베이스의 상태를 일치시킵니다.

flush는 다음 시점에 자동으로 발생합니다:

  • 트랜잭션 commit 시점: 트랜잭션이 종료될 때 변경 사항을 데이터베이스에 반영합니다.
  • JPQL 실행 시점: JPQL 쿼리를 실행하기 전 flush가 실행되어 쿼리가 최신 상태의 데이터를 기반으로 동작합니다.
  • Native Query 실행 시점: JPQL과 동일하게 실행 전에 flush가 발생합니다.

또한 flush()를 통해서 개발자가 명시적으로 호출하여 flush를 발생시킬 수 있습니다.

Q. flush와 clear의 차이점은 무엇인가요?

더보기

 

  • flush: 영속성 컨텍스트의 변경 사항을 데이터베이스에 동기화하지만, 영속성 컨텍스트는 유지됩니다.
  • clear: 영속성 컨텍스트를 초기화하여 관리 중인 모든 엔티티를 제거합니다. 이후에는 해당 엔티티에 대해 데이터베이스 접근이 필요합니다.

 

Q. Dirty Checking과 flush의 관계에 대해 설명해보세요.

더보기

Dirty Checking은 JPA가 영속성 컨텍스트에 있는 엔티티를 주기적으로 감시하여 변경된 상태를 감지하는 메커니즘입니다.

  • Dirty Checking 동작 과정:
    1. 엔티티의 필드 값이 변경되면 JPA가 이를 감지합니다.
    2. 변경된 내용을 기록하고 flush 시점에 적절한 SQL(INSERT, UPDATE 등)을 생성합니다.
    3. flush가 호출되면 데이터베이스에 반영됩니다.

따라서 Dirty Checking은 flush가 실행되기 전에 발생하며, 변경 사항이 있는 경우에만 flush가 의미를 갖습니다.

Q. 대량 데이터를 처리할 때 flush는 어떻게 관리해야 하나요?

더보기

대량 데이터를 처리할 때는 flush와 clear를 주기적으로 호출하여 영속성 컨텍스트의 메모리 사용량을 관리해야 합니다.

for (int i = 0; i < entities.size(); i++) {
    entityManager.persist(entities.get(i));
    if (i % 50 == 0) { // 50개 단위로 처리
        entityManager.flush(); // 변경 사항을 데이터베이스에 반영
        entityManager.clear(); // 영속성 컨텍스트 초기화
    }
}
 

이 방법은 메모리 오버헤드를 방지하고 성능을 최적화하는 데 유용합니다.

Q. FlushModeType.AUTO와 FlushModeType.COMMIT의 차이점은 무엇인가요?

더보기
  • FlushModeType.AUTO (기본값): JPQL 실행이나 트랜잭션 commit 전에 자동으로 flush가 발생합니다. 일반적인 개발 상황에서 사용됩니다.
  • FlushModeType.COMMIT: flush가 오직 트랜잭션 commit 시점에만 발생합니다. 데이터베이스 동기화 빈도를 줄여 성능을 최적화할 수 있습니다.

 

  • AUTO는 일반적인 CRUD 작업에 적합하며, 데이터 일관성을 중요하게 여길 때 사용합니다.
  • COMMIT은 대량 데이터 처리와 같은 성능이 중요한 작업에서 사용합니다.

 

 

728x90
반응형