본문 바로가기
Framework and Tool/JPA

JPA - 영속성 관리 - 플러시(flush)

by ocwokocw 2021. 6. 24.

- 참조: 자바 ORM 표준 JPA 프로그래밍

- 플러시

플러시(flush())는 영속성 컨텍스트의 변경 내용을 DB에 반영하는 연산이다. 플러시를 수행하면 

  • 변경 감지 -> 영속성 컨텍스트의 엔티티와 스냅샷 비교 -> 수정된 엔티티 수정 쿼리 생성 -> 쓰기 지연 SQL 저장소 등록
  • 쓰기 지연 SQL 저장소 -> DB 로 쿼리 전송

영속성 컨텍스트의 플러시는 3 가지 방법으로 수행할 수 있다.

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

em.flush() 를 직접 호출하면 영속성 컨텍스트를 강제로 플러시한다. 하지만 이는 거의 사용하지 않는 기능이다.

 

트랜잭션 커밋시 자동 호출되어야 하는 이유는 flush() 와 COMMIT 이 다르기 때문이다. flush() 는 우리가 DB Editor 에서 SQL 을 작성하는것이라고 할 수 있으며, 트랜잭션 커밋은 말 그대로 COMMIT 을 수행하는것이다. SQL을 쓰지 않고 COMMIT을 수행한다면 당연히 어떤 일도 일어나지 않는다. 트랜잭션 커밋시 flush() 가 자동호출 되는 이유가 바로 이 때문이다.

 

JPQL 이나 Criteria 쿼리 실행시에도 플러시가 자동 호출되는데 예제코드를 하나 보자.

 

Member member1 = new Member();
member1.setId("ID#1");
member1.setUserName("ocwokocw1");
member1.setAge(31);

em.persist(member1);

Member member2 = new Member();
member2.setId("ID#2");
member2.setUserName("ocwokocw2");
member2.setAge(32);

em.persist(member2);

Member member3 = new Member();
member3.setId("ID#3");
member3.setUserName("ocwokocw3");
member3.setAge(33);

em.persist(member3);

List<Member> members = em.createQuery("select m from Member m", Member.class)
.getResultList();
System.out.println("members size: " + members.size());

System.out.println("flush test");

 

위의 코드에서 member1,2,3 을 영속화 시키면 아직 영속성 컨텍스트에만 있고 DB 에는 반영이 되지 않은 상태이다. 그런데 이때 JPQL 로 DB 에서 조회하면 member1,2,3 은 조회되지 않는다. 이런 문제를 예방하기 위해 JPA 에서는 JPQL 을 실행할 때 플러시를 호출한다. (find() 연산은 호출하지 않는다.)

 

위의 코드에서 System.out.println("flush test") 부분에 디버깅을 걸어놓고 코드를 수행해보면 commit 이 되지 않아도 아래 실행결과가 나타나는것을 알 수 있다.

 

Hibernate: 
    /* insert com.example.demo.member.Member
        */ insert 
        into
            MEMBER
            (age, NAME, ID) 
        values
            (?, ?, ?)
Hibernate: 
    /* insert com.example.demo.member.Member
        */ insert 
        into
            MEMBER
            (age, NAME, ID) 
        values
            (?, ?, ?)
Hibernate: 
    /* insert com.example.demo.member.Member
        */ insert 
        into
            MEMBER
            (age, NAME, ID) 
        values
            (?, ?, ?)
Hibernate: 
    /* select
        m 
    from
        Member m */ select
            member0_.ID as id1_0_,
            member0_.age as age2_0_,
            member0_.NAME as name3_0_ 
        from
            MEMBER member0_
members size: 3

- 플러시 옵션

엔티티 매니저의 플러시 모드를 변경할 수 있다. javax.persistence.FlushModeType 을 사용하면 된다. AUTO 와 COMMIT 이 있으며 AUTO는 커밋이나 쿼리 실행할 때 플러시를 하고, COMMIT 은 커밋할때만 플러시를 한다. 기본값은 AUTO 이다.

 

플러시 옵션은 성능 최적화를 위해 사용하는 경우가 있으며 이는 나중에 살펴보기로 한다. 또 한 가지 주의사항이 있는데 플러시는 영속성 컨텍스트에 보관된 엔티티를 DB에 동기화하는것이지 지우는것은 아니다.

댓글