본문 바로가기

JPA

Flush란?

플러시

  • 플러시(Flush)란, 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영(동기화)하는 작업이다.
    • em.persist 등으로 쓰기 지연 SQL 저장소에 쌓아두었던 SQL 쿼리들을 실제 데이터베이스로 전송하는 것이다.
  • 플러시가 발생하면 내부적으로 다음과 같은 일이 순차적으로 일어난다.
    1. 변경 감지(Dirty Checking) 수행
      • 영속성 컨텍스트에 의해 관리되고 있는 모든 엔티티에 대하여 1차 캐시의 현재 상태와 스냅샷 원본을 비교하여 변경된 부분을 감지한다.
    2. 수정 엔티티에 대한 SQL Query 생성
      • 변경 감지로 통해서 수정 사항이 있는 경우 SQL 쿼리를 생성하여 쓰기 지연 SQL 저장소에 추가한다.
    3. 쓰기 지연 SQL 저장소의 쿼리를 DB로 전송
      • 실제로 저장소에 쌓여 있는 모든 SQL 쿼리를 데이터베이스로 전송하여 반영한다.
  • 플러시가 발생하는 시점
    • 트랜잭션 커밋시 자동으로 플러시 호출.
      • 트랜잭션 커밋 시에 JPA가 내부적으로 flush()를 자동 호출하여 DB에 동기화 후 완료한다.
    • JPQL 쿼리 실행시 자동으로 플러시 호출.
      • 이 경우는 예시를 들어야 이해가 쉽다. 쉬운 예시로 persist로 멤버 엔티티를 영속화 시켰는데, 이 시점에서는 아직 쿼리가 날라가지 않은 상태일 것이다.(쓰기 지연 SQL 저장소 안에 SQL 쿼리만 생성되어 추가되어 있을 것임) 만약 여기서 커밋 전에 JPQL 쿼리를 사용하여 해당 멤버 엔티티를 조회하려고 하면 당연히 DB 내에 그 엔티티가 존재하지 않아서 오류가 발생할 것이다. 이를 방지하기 위해서 JPA는 자동으로 영속성 컨텍스트의 변경 내용을 먼저 반영하고 해당 쿼리를 실행하여 정상으로 작동하도록 설계되어 있다.
    • 직접 플러시 호출하는 경우
      • em.flush()로 직접 호출할 수 있으나, 특별한 경우가 아닐 경우 자동 사용을 권장한다.
  • 플러시 모드 옵션
    • FlushModeType.COMMIT → JPQL 쿼리 실행 시에는 플러시를 호출하지 않고, 트랜잭션 커밋 시점에만 자동으로 플러시를 호출한다.
    • FlushModeType.AUTO → 트랜잭션 커밋 시점이나 JPQL 쿼리 실행 시점에만 자동으로 Flush를 호출한다.(기본값)
  • 플러시에 대한 오해
    • 플러시는 영속성 컨텍스트를 비우는게 아니다. 그냥 변경 내용을 데이터베이스에 동기화 시켜줄 뿐이고 영속성 컨텍스트 내부 내용은 그대로 유지된다.
    • Flush는 영속성 컨텍스트의 SQL 쿼리를 DB에 전송하는 작업을 하고 Commit은 Flush까지 마친 마지막 작업 결과를 DB에 영구적으로 저장하고 트랜잭션을 종료하는 작업을 한다.