영속성 컨텍스트
-
엔티티를 영구 저장하는 환경 EntityManager.persist(엔티티);
-
엔티티 매니저로 엔티티를 저장하거나 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
-
논리적인 개념, 엔티티 매니저 생성시 하나가 만들어진다.
-
여러 엔티티 매니저가 같은 영속성 컨텍스트에 접근할 수 있다.
엔티티의 생명주기
-
비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태
-
영속 (managed) : 영속성 컨텍스트에 저장된 상태
-
준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
-
삭제 (removed) : 삭제된 상태
영속성 컨텍스트 특징
- 엔티티를 식별자 값으로 구분한다. => 영속상태는 식별자 값이 반드시 있어야한다. 없으면 예외 발생
- jpa는 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 저장된 엔티티를 db에 반영 => flush()
엔티티 조회
- 영속성 컨텍스트는 내부에 1차 캐시를 가지고 잇는데 엔티티는 모두 이곳에 저장된다 => 즉, Map이 있으면 키는 @Id로 매핑한 식별자고 값은 엔티티 인스턴스
- find() 메소드 사용시 1차 캐시에서 엔티티를 찾고 여기에 없으면 db에서 조회한다.
- db에서 조회할 경우 엔티티를 생성하고 1차 캐시에 저장한 후에 영속 상태의 엔티티를 반환한다.
영속 엔티티의 동일성 보장
동일성(identity) : 실제 인스턴스가 같다. == 비교의 값이 같다.
동등성(equality) : 실제 인스턴스는 다를 수 있지만 인스턴스가 가지고 있는 값이 같다.
Member a = entitymanager.find(Member.class, "m1");
Member b = entitymanager.find(Member.class, "m1");
System.out.println(a == b);
- entitymanager.find(Member.class, "m1")를 반복해서 호출해도 영속성 컨텍스트는 1차 캐시에 있는 같은 엔티티 인스턴스를 반환한다.
쓰기지연(transactional write-behind)
- 엔티티 매니저는 트랜잭션을 커밋하기 내부 쿼리 저장소에 INSERT SQL을 모아둔다.
- 그리고 commit할 때 모아둔 쿼리를 db에 보낸다.
- commit하면 영속성 컨텍스트를 flush 한다. flush는 영속성 컨텍스트의 변경 내용을 db에 동기화하는 작업
변경 감지(dirty checking)
- 엔티티의 변경사항을 db에 자동으로 반영하는 기능
- 엔티티를 영속성 컨텍스트에 보관할때 최초 상태를 복사해서 저장해두는데 이것을 스냅샷이라 한다.
- 그리고 플러시 시점에 스냅샷과 엔티티를 비교해서 변경된 엔티티를 찾는다.
- 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.
엔티티 삭제
- entitymanager.remove(0에 삭제 대상 엔티티를 넘겨주면 엔티티를 삭제한다. 호출하는 순간 영속성 컨텍스트에서 제거된다.
- 삭제 쿼리를 쓰기 지연 sql 저장소에 등록한다.
flush()
- 영속성 컨텍스트의 변경 내용을 db 에 반영한다.
- 변경감지가 동작하여 스냅샷과 비교하여 수정된 엔티티를 찾고, 수정 쿼리를 만들어 쓰기 지연 SQL 저장소에 등록한다.
- 쓰기 지연 SQL 저장소의 쿼리를 DB 에 전송한다.
flush 하는 방법
- entitymanage.flush() 를 직접 호출한다. => 강제, 거의 사용하지 않는다.
- 트랜잭션 커밋 시 플러시가 자동 호출된다.
- JPQL 쿼리 실행 시 플러시가 자동 호출된다. => JPQL 실행시 SQL로 변환되어 DB에서 엔티티를 조회하는데 DB에 없으므로 조회가 되지 안흔다. 따라서 쿼리 실행 직전에 flush가 자동으로 호출된다.
플러시 모드 옵션
- FlushModeType.AUTO : 커밋이나 쿼리를 실행할 때 플러시(기본값)
- FlushMdoeType.COMMIT : 커밋할 때만 플러시