[JPA] 플러시(flush)
플러시(flush)란?
영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것을 의미한다.
아래 경우에 flush가 발생한다.
- 트랜잭션에 commit이 발생할 때
- EntityManager의 flush 메서드를 호출했을 때
- JPQL 쿼리가 실행될 때
그리고 flush가 발생하면 쓰기 지연 저장소에 저장된 SQL(INSERT/UPDATE/DELETE)이 데이터베이스로 전송된다.
IO 처리 시 FileStream.flush() 메서드를 사용하는 경험이 있어 flush 발생 시 영속성 컨텍스트가 비워지는 것이 아닌지 헷갈릴 수 있으나, 아니다. flush가 발생한다고 해서 영속성 컨텍스트가 비워지는 것이 아니고, 변경 사항을 DB와 동기화 하는 것을 의미한다. 그러한 이유로 flush가 발생해도 1차 캐시는 유지된다.
위 세가지 경우에서 JPQL 쿼리가 실행될 때 flush가 발생하는 이유는 무엇일까? 아래 코드를 보자.
em.persist(memberA); // 영속성 컨텍스트에 memberA가 추가됨
em.persist(memberB); // 영속성 컨텍스트에 memberB가 추가됨
em.persist(memberC); // 영속성 컨텍스트에 memberC가 추가됨
// JPQL 실행
query = em.createQuery("select m from Member m", Member.class);
List<Member> members= query.getResultList(); // ???
em.persist 메서드 수행 시 각각의 Member 객체가 영속성 컨텍스트에 추가되어 영속 상태가 되는데, 그 이후 JPQL로 전체 Member 목록을 조회하도록 하고 있다.
이때, 만약 JPQL 수행 시 flush가 발생하지 않는다면 어떻게 될까? JQPL로 조회한 members 리스트에는 위에서 추가한 memberA, memberB, memberC가 포함되지 않는 문제가 생긴다. JPA에서는 이러한 문제를 예방하기 위해 JPQL 수행 전 자동으로 flush를 발생시켜 DB와 영속성 컨텍스트간의 동기화를 수행하도록 하고 있다.
때문에, members 리스트에는 memberA, memberB, memberC가 포함되어 조회되는 것이다.
플러시 동작 과정
- 영속성 컨텍스트에서 변경을 감지한다. → Dirty Checking
- 수정이 발생한 Entity를 지연 SQL 저장소에 등록한다.
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스로 전송한다.
주의할 점은, 데이터베이스에는 트랜잭션이라는 작업 단위가 존재하기 때문에 한 트랜잭션 내에서 flush가 아무리 발생해도 DB commit은 발생하지 않는다는 점이다. DB commit은 해당 트랜잭션이 commit 될 때 발생한다.
플러시 모드 옵션
- FlushModeType.AUTO : 커밋이나 쿼리를 실행할 때 플러시 (default)
- FlushModeType.COMMIT : 커밋할 때만 플러시
출처 :: 인프런 강의(자바 ORM 표준 JPA 프로그래밍 - 기본편)