DEV ℧ Developer Diary

[JPA] 플러시

해당 포스트는 인프런 김영한님의 자바 ORM 표준 JPA 프로그래밍 - 기본편 을 듣고 정리한 글입니다.

플러시

영속성 컨텍스트의 변경내용을 데이터 베이스에 반영 보통 데이터베이스에 커밋할때 해당 상태가 이루어진다. 간단하게 말하자면 영속성 컨텍스트의 변경사항과 DB를 맞춰주는 역할을 한다.

플러시 발생

  • 변경 감지
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송 (등록, 수정, 삭제 쿼리)

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

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

flush() 직접 호출

em.flush()를 사용하면 커밋 전에 SQL 쿼리를 만들어 DB에 적용 할 수 있다.

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("hello");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();

entityTransaction.begin();
try {
    log.debug("member persist - BEFORE");
    Member member = new Member(105L, "member200");
    entityManager.persist(member);
    log.debug("member persist - AFTER");

    log.debug("member flush - BEFORE");
    /* 쿼리 생성 */
    entityManager.flush();
    log.debug("member flush - AFTER");

    entityTransaction.commit();
} catch (Exception e) {
    entityTransaction.rollback();
} finally {
    entityManager.close();
}
entityManagerFactory.close();
23:46:54.242 [main] DEBUG com.dhaudgkr.jpastart.hellojpa.JpaPersistent - member persist - BEFORE
23:46:54.263 [main] DEBUG com.dhaudgkr.jpastart.hellojpa.JpaPersistent - member persist - AFTER
23:46:54.263 [main] DEBUG com.dhaudgkr.jpastart.hellojpa.JpaPersistent - member flush - BEFORE
23:46:54.289 [main] DEBUG org.hibernate.SQL -
    /* insert com.dhaudgkr.jpastart.hellojpa.entity.Member
        */ insert
        into
            Member
            (name, id)
        values
            (?, ?)
23:46:54.304 [main] DEBUG com.dhaudgkr.jpastart.hellojpa.JpaPersistent - member flush - AFTER

em.flush()를 사용한다고 해서 1차캐시가 날라가는 것은 아니다. 영속성에 올라간 entity와 쓰기 지연 SQL, 변경감지 등등이 반영되는 것이다.

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();

각 memberA, memberB, memberC를 영속성으로 저장한 상태는 DB에 반영이 된상태가 아니다. 하지만 JPQL은 쿼리로 변환해서 DB로 날려 데이터를 가져오는 것이기 때문에, 데이터의 정합성을 위해 미리 flush를 실행시켜 쓰기 지연 SQL에 들어있는 쿼리를 반영하고 JPQL을 실행한다.

플러시 모드 옵션

em.setFlushMode(FlushModeType.COMMIT)
  • FlushModeType.AUTO : 커밋이나 쿼리를 실행할 때 플러시 (기본값)
  • FlushModeType.COMMIT : 커밋할 때만 플러시 (중간에 실행되는 JPQL이 영속성에 담겨있는 엔티티와 전혀 상관 없을때 쓰이곤 한다.)

플러시 정리

  • 영속성 컨텍스트를 비우지 않는다.
  • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
  • 트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화 하면 됨