본문 바로가기

Spring/JPA

영속성 컨텍스트 플러시

플러시는 영속성 컨텍스트의 변경 내용을 DB에 반영합니다. 보통 DB 트랜잭션이 커밋될 때 영속성 컨텍스트에서 플러시가 자동으로 일어납니다. 영속성 컨텍스트에서 플러시가 발생되면 엔티티의 변경을 감지하고 수정된 엔티티가 있다면 UPDATE SQL을 쓰기 지연 SQL 저장소에 저장합니다. 이후에 쓰기 지연 SQL 저장소에 저장된 쿼리(등록, 수정, 삭제 쿼리)를 DB에 전달합니다. 

 

영속성 컨텍스트가 플러시 되었다고 해서 영속성 컨텍스트의 1 캐시가 지워지지 않습니다. 플러시는 쓰기 지연 SQL 저장소에 있는 쿼리들을 DB 반영되는 과정입니다.

 

아래와 같은 방법으로 영속성 컨텍스트를 플러시 있습니다.

    • em.flush() : 플러시를 직접 호출하는 방법입니다.
    • 트랜잭션 커밋 : 플러시가 자동으로 호출됩니다.
    • JPQL 쿼리 실행 : 트랜잭션 커밋의 경우와 동일하게 플러시가 자동으로 호출됩니다.

직접 플러시를 호출하는 방식과 트랜잭션이 커밋될 플러시가 호출되는 상황은 이해되지만, JPQL 쿼리를 실행할 플러시가 자동으로 호출될까요? 아래 코드로 살펴봅시다.

// 영속성 컨텍스트가 플러시되지 않아 em.persist 했을 때 DB에 바로 저장되지 않습니다.
em.persist(member1);
em.persist(member2);
em.persist(member3);

// 트랜잭션 커밋 전에 조회를 위해 JPQL을 실행하면 위의 세 번의 persist에 의해 DB에 데이터가 저장되어 있어야 합니다.
// 따라서 JPQL 쿼리가 실행되면 플러시가 자동 호출되어 이전의 엔티티를 DB에 업데이트합니다.
query = em.createQuery("select m from Member m", Member.class);
List<Member> members = query.getResultList();

 

JPQL 쿼리를 실행하는 경우에는 특정 조건으로 DB의 데이터를 조회해야 할 경우입니다. 따라서 위 코드처럼 persist로 추가한 엔티티가 영속성 컨텍스트에만 존재하고 DB에 추가되지 않았을 때 해당 엔티티를 JPQL 쿼리로 조회하게 되면 DB에 없는 엔티티를 조회한 꼴이 됩니다. 이를 막기 위해 JPQL 쿼리를 실행했을 때 영속성 컨텍스트를 플러시 하여 이전에 쓰기 지연 SQL 저장소에 저장한 SQL을 DB에 날려 업데이트합니다. 따라서 persist 이후 바로 JPQL 쿼리로 해당 엔티티를 조회해도 문제가 발생하지 않도록 할 수 있습니다.

 

다시 말해 플러시는 영속성 컨텍스트의 변경 내용을 DB에 동기화하는 것이지 영속성 컨텍스트를 비우는 게 아닙니다. 플러시가 동작할 수 있는 메커니즘은 트랜잭션이라는 작업 단위에 있기 때문에, 트랜잭션과 영속성 컨텍스트의 생명주기를 동일하게 가져가야 데이터 동기화 등에 문제가 없습니다.

 

기본적으로 엔티티 매니저는 트랜잭션 커밋일 때와 JPQL 쿼리가 실행되었을 플러시가 자동 호출되는 FlushModeType.AUTO 설정되어 있습니다. setFlushMode 함수로 아래 코드와 같이 플러시 모드를 FlushModeType .COMMIT으로 변경하면 트랜잭션이 커밋될 때만 플러시가 되도록 있지만, FlushModeType 직접 수정하는 일은 없고 기본적인 FlushModeType.AUTO 사용하는 좋습니다.

em.setFlushMode(FlushModeType.AUTO);
em.setFlushMode(FlushModeType.COMMIT);

'Spring > JPA' 카테고리의 다른 글

일대일 연관관계 매핑  (1) 2024.10.17
연관관계 매핑 기초  (1) 2024.10.17
기본키 매핑  (0) 2024.10.17
영속성 컨텍스트  (2) 2024.10.16
JPA가 등장한 배경  (0) 2024.10.16