플러시 : flush()
플러시란 영속성 컨텍스트의 변경 내용들이 데이터베이스에 반영하는 것을 의미.
즉 현재 변경 사항과 DB데이터의 값을 맞추는 작업 -> 실제 SQL이 DB에 날라감
대체로 트랜잭션 커밋시 플러시가 발생한다.
플러시 호출시 JPA가 변경을 감지하여 이전의 스냅샷과 비요하여 수정된 엔티티에 대한 쿼리를 쓰기 지연 SQL 저장소에 등록한 후, 이를 실제 DB에 전송한다.
플러시가 언제, 어떻게 발생할 수 있을까?
1. em.flush()로 직접 호출하면 플러시가 발생한다. (거의 쓸일이 없지만 테스트용으로는 많이 씀 + 커밋하기 전 먼저 SQL을 즉시 전송할 때)
2. 트랜잭션 commit 자동 플러시 호출 -> 주로 이 방식이 사용된다.
3. JPQL 커밋시 자동 플러시 호출 ->
이전에 예시를 기억해보면, persist만으로는 실제 쿼리가 날라가지 않는다.
근데 만약 데이터를 persist로 잔뜩 등록해놓고, 그 다음 줄에 JPQL을 통해 persist 한 데이터를 호출하면 어떻게 될까?
당연히 조회 되지 않는다. 아직 DB에 쿼리가 날라가지 않았기 때문이다. 그리고 JPQL은 결국 SQL로 번역되어 DB에 전송되기 때문에, persist만 한 영속 엔티티를 조회할 수 없다.
그래서 오류와 예외를 방지하고자, JPQL 실행시 일단 먼저 플러시가 한번 일어난다. 그 이후에 변경이 반영된 DB에서 데이터를 다시 영속성 컨텍스트에 퍼 올린다.
플러시를 하면 1차 캐시가 다 비워지나?
아니다. 플러시를 한다고 해서 1차 캐시가 지워지는게 아니고, 쓰기 지연 SQL 저장소의 쿼리 즉시 전송 + 변경 감지가 일어나 DB에 반영될 뿐, 영속성 컨텍스트가 비워지는 건 아니다.
플러시는 결국 영속성 컨텍스트의 변경 내용을 DB에 동기화 (최신화) 하는 작업일 뿐이고, 트랜잭션이 커밋 되기 직전까지 반드시 한번만 일어나면 된다.
준영속 상태
엔티티를 영속화 하는 방법은 두가지다.
em.persist() 를 통해 직접 영속화 시키는 방법 + find() 를 통해 1차캐시 확인후 데이터가 없으면 DB에서 실제로 가져와서 영속화 시키는 방법이 있다.
영속성 컨텍스트에 영속된 엔티티를 영속성 컨텍스트에서 분리되어 나온 상태이다. 영속성 컨텍스트에서 빠져나왔기 때문에, Dirty Checking 등의 영속성 컨텍스트의 기능을 사용할 수 없게 된다.
준영속 상태로 만드는 방법
em.detach(member); // 특정 엔티티만 준영속화
em.clear(); // 영속성 컨텍스트 아예 초기화 (1차 캐시 비우기)
em.close(); // 영속성 컨텍스트 자체를 종료