본문 바로가기
JPA

자바 ORM 표준 JPA 프로그래밍 - Flush

by 임동무 2023. 2. 8.

Flush

flush 는 '변기물을 내리다, 물로 씻어내다' 라는 뜻을 가진다. 

JPA 에서 이 의미를 사용하며 쿼리들을 모아서 날리는 작업을 flush 라고 한다.

 

 


JPA에는 영속성 컨텍스트라는 1차캐시 개념이 존재한다. 

우리가 객체를 생성하고 엔티티 매니저를 통해 영속화 하면 해당 객체는 영속성 컨텍스트에 저장된다.

 

아래 코드를 보자.

em.persist(memberA);	//memberA 영속
em.persist(memberB);	//memberB 영속
em.persist(memberC);	//memberC 영속
em.persist(memberD);	//memberD 영속
em.persist(memberE);	//memberE 영속

 

위 상황에서 영속할 때마다 쿼리를 날린다고 생각하면

em.persist(memberA);	//insert ...
em.persist(memberB);	//insert ...
em.persist(memberC);	//insert ...
em.persist(memberD);	//insert ...
em.persist(memberE);	//insert ...

로 5개의 쿼리가 날라간다. 하지만 여기서

문제는 memberA 를 DB에 저장하면서 네트워크 호출, 나머지 B~E 까지 마찬가지로 네트워크를 호출하면서 

총 5번의 네트워크 호출이 이루어진다.

 

 

이 작업을 최적화 하기 위해서 가장 간단하게 드는 생각은 

"아니 쿼리를 그냥 한 번에 다 모아서 보내버리면 안돼?" 일 것이다.

 

그게 바로 플러시 이다.

 

 

 

JPA 는 트랜잭션을 지원하는 쓰기지연 (transactional write-behind) 를 통해
영속성 컨텍스트에 변경사항이 생길 때 마다

SQL 저장소에 SQL 을 생성 및 저장한다. 이 SQL 저장소에 저장된 SQL 을 실행하여
현재 변경사항을 데이터 베이스에 반영하는 것이 플러시이다.

 

다만 주의할 점은 플러시는 영속성 컨텍스트를 비우는 것이 아니라, 지금까지 SQL 저장소에 저장된 SQL 을 단순히 실행시키는 것이다.

 


플러시를 하는 방법은 총 3가지가 있다.

 

1. entityManager.flush() 를 호출하여 직접 플러시하는 방법

2. 트랜잭션을 커밋하여 자동으로 플러시 하는 방법

3. JPQL 쿼리를 실행 시 플러시 자동 호출

 

1. 직접 호출

 첫 번째, flush() 를 직접 호출하는 방법은 테스트를 제외하면 거의 사용하지 않는다.

 

2. 트랜잭션 커밋

 두 번째, 트랜잭션을 커밋하여 자동으로 플러시를 하는 방법이다. 현재 DB 와의 변경사항을 저장해야 하는 상황에서 flush() 를 호출하지 않은 채로 트랜잭션을 커밋해버리면 DB에 변경사항이 저장되지 않는 문제가 발생한다. 이를 방지하기 위해서 트랜잭션을 커밋할 때 자동으로 플러시가 호출된다.

 

3. JPQL 실행

 세 번째, JPQL 쿼리를 실행하는 경우이다. 현재 DB 에 memberA~E 가 저장되어 있고 memberF 를 영속했다고 가정하자. 이 때, JPQL 쿼리로 현재 member 를 모두 조회했을 때, 플러시가 자동으로 호출되지 않는다면 memberA~E 만 호출이 될 것이다. 

즉, DB 가 동기화 되지 않아서 문제가 발생한다. 이 문제를 해결하기 JPQL 쿼리를 실행하기 전에 자동으로 플러시를 호출하여 동기화를 시켜준다

 

 

하지만, 플러시에서 가장 중요한 것은 트랜잭션 이라는 작업 범위이다.

 

플러시를 할 때에는 트랜잭션이 커밋 되기 직전에만 동기화를 시켜주면 된다.

 

댓글