JPA-시작하기 에서 어느 정도 영속성 컨텍스트와 엔티티의 생명주기를 간단하게 알아봤다. 이 영속성 컨텍스트의 특징을 좀 더 자세히 알아보도록 하자.
플러시
플러시는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다. 이 때 영속성 컨텍스트에 보관된 엔티티를 지우는 것은 아니다. 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화 하는 것이다.
플러시 과정
- 변경 감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샷과 비교하여 수정된 엔티티를 찾는다.
- 수정된 엔티티는 수정 쿼리를 만들어서 쓰기 지연 SQL 저장소에 등록한다.
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송한다.
플러시 방법
em.flush()
를 직접 호출한다. 테스트나 다른 프레임워크와 JPA를 함께 사용할 때를 제외하고는 거의 사용하지 않는다.- 트랜잭션 커밋 시 플러시가 자동 호출된다.
- JPQL 쿼리 실행 시 플러시가 자동 호출된다. JPQL을 실행하면 JPQL이 SQL로 변환되어 데이터베이스에서 엔티티를 조회한다. SQL 쿼리를 실행하기 위해서는 영속성 컨텍스트를 플러시해서 변경 내용을 데이터베이스에 반영해야 하기 때문에 플러시가 발생한다.
플러시 모드 옵션
FlushModeType.AUTO
: 커밋이나 쿼리를 실행할 때 플러시(기본값)FlushModeType.COMMIT
: 커밋할 때만 플러시
준영속
영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 것을 준영속 상태라고 한다. 준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.
준영속 상태로 만드는 방법
아래와 같은 3가지 방법이 있다. 참고로 영속 상태의 엔티티가 준영속 상태로 변할 때 1차 캐시와 관련된 쓰기 지연 SQL 저장소 관련 SQL이 제거되고 데이터 베이스에 플러시가 발생하지는 않는다.
em.detach(eitity)
: 특정 엔티티를 준영속 상태로 전환한다.em.clear()
: 영속성 컨텍스트를 완전히 초기화한다.em.close()
: 영속성 컨텍스트를 종료한다.
병합: merge()
준영속 상태의 엔티티를 다시 영속 상태로 변경하려면 사용할 수 있는 메소드다.
Member mergeMember = em2.merge(member);
위 코드를 호출하면 mergeMember
는 영속 상태가 된고 member
는 여전히 준영속 상태이다. 위 메소드를 호출하면 영속 컨텍스트와 DB를 통해 동일한 id를 가진 엔티티를 찾은 후 업데이트 시킨다. 해당 id가 존재하지 않을 경우 새로운 영속 상태의 엔티티를 만들어준다.
참고 자료
자바 ORM 표준 JPA 프로그래밍 (김영한) https://stackoverflow.com/questions/1069992/jpa-entitymanager-why-use-persist-over-merge
댓글남기기