플러시

작성일

플러시란?

플러시(flush())는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.

플러시를 실행하면 다음과 같은 일이 발생한다.

  1. 변경 감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교하여 수정된 엔티티를 찾는다.
  2. 수정된 엔티티는 쓰기 지연 SQL 저장소에 등록한다.
  3. 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송한다. (등록, 수정, 삭제 쿼리)

영속성 컨텍스트를 플러시하는 방법

참고
직접 플러시를 할일은 많이 없지만 테스트 시 사용하는 경우가 있기 때문에 알고는 있어야 한다.

  • em.flush() - 직접 호출
  • 트랜잭션 커밋 - 플러시 자동 호출
  • JPQL 쿼리 실행 - 플러시 자동 호출

직접 호출

엔티티 매니저의 flush() 메서드를 직접 호출해서 영속성 컨텍스트를 강제로 플러시한다. (거의 사용하지 않는다.)

em.flush();

트랜잭션 커밋 시 자동 호출

데이터베이스에 Update SQL을 전달하지 않고 트랜잭션만 커밋하면 변경 내용이 반영되지 않는다. 따라서 트랜잭션 커밋 시 fluah()를 호출해야 하는데 JPA는 이런 문제를 예방하기 위해 트랜잭션 커밋 시 자동으로 flush()를 호출한다.

JPQL 실행 시 자동 호출

아래 예제를 살펴보자.

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

// 중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.class);
List<Member> members= query.getResultList();

em.persist()를 해도 데이터베이스에 Insert 되는 시점은 트랜잭션 커밋 시점이므로 원래 같으면 JPQL로 조회 시 데이터가 조회되지 않는다. JPA에서는 이를 방지하기 위해 JPQL을 실행 시 자동으로 flush() 후 데이터를 가져오게 되어있다.

참고 flush()를 하게 되면 1차 캐시가 지워질까?
아니다. flush()는 단순히 쓰기 지연 SQL 저장소의 쿼리를 DB에 반영하는 역할만 한다.

플러시 모드 옵션

엔티티 매니저에 플러시 모드를 직접 지정하려면 javax.persistence.FlushModeType을 사용하면 된다.

  • FlushModeType.AUTO: 커밋이나 쿼리를 실행할 때 플러시 (기본값)
  • FlushModeType.COMMIT: 커밋할 때만 플러시
em.setFlushMode(FlushModeType.COMMIT);

대부분 AUTO 기본 설정을 그대로 사용하고 COMMIT 모드는 성능 최적화를 위해 사용한다.

결론

플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 것이다. (영속성 컨텍스트에 보관된 엔티티를 지우는 것이 아니다.) 데이터베이스와 동기화를 늦추는 것이 가능한 이유는 트랜잭션이라는 작업 단위가 있기 때문이다. 트랜잭션 커밋 직전에만 변경 내용을 데이터베이스에 보내 동기화하면 된다.

카테고리: