영속성 컨텍스트(Persistence Context)란?
Entity의 생명주기
비영속(new/transient)
Member member = new Member();
member.setName("김도진");
영속(managed)
Member member = new Member();
member.setName("김도진");
entityTransaction.begin();
entityManager.persist(member);
- 영속성 컨텍스트(1차 캐시)에 저장된 상태
- 영속 상태로 만드는 방법 2가지
entityManager.persist(entity)
: Entity를 영속성 컨텍스트에 저장
entityManager.find(Entity.class, id)
: DB에서 영속성 컨텍스트로 불러오기
준영속(detached)
entityManager.detach(member);
- 영속성 컨텍스트에 저장되었다가 분리된 상태 (더이상 DB에 영향받지 않음)
- 준영속 상태로 만드는 방법
entityManager.detach(entity)
: 특정 엔티티를 준영속 상태로 변경
entityManager.clear()
: 영속성 컨텍스트 초기화
entityManager.close()
: 영속성 컨텍스트 종료
삭제(removed)
entityManager.remove(member);
- 삭제 상태 (커밋 시점에 DB에서 DELETE)
영속성 컨텍스트의 기능
1차 캐시
- 같은 트랜잭션 내에서 같은 id를 2번 이상 조회하는 경우 DB에 SQL을 보내지 않고 1차 캐시에서 조회하여 성능 향상
- 실제로 한 트랜잭션 내에서 2번 이상 조회하는 로직은 거의 없기 때문에 효과는 미미하다
동일성 보장
- 같은 트랜잭션 내에서 같은 id를 2번 이상 조회하는 경우 1차 캐시에서 조회하므로 동일한 메모리 주소 참조
쓰기 지연
- INSERT, UPDATE, DELETE가 발생하면 쓰기 지연 SQL 저장소에 모아놨다가 커밋하는 순간 DB와 통신해서 SQL 실행
변경 감지(Dirty Checking)
- 1차 캐시에 Entity가 영속된 시점의 스냅샷을 가지고 있다가 flush가 발생했을 때 현재 상태와 비교
- 변경이 감지되면 UPDATE SQL 생성 및 DB에서 실행
지연 로딩
- 객체를 사용하는 시점에 DB에 SQL을 보내서 조회
- Ex. Entity의 ID를 제외한 필드를 getter 등으로 불러오는 시점
flush
- 영속성 컨텍스트의 변경 내용을 DB에 전송(커밋 아님)
- 영속성 컨텍스트를 비우지 않는다
- flush 시점에 변경 감지 실행(UPDATE)
- 쓰기 지연 SQL 저장소의 쿼리를 DB에 전송(INSERT, UPDATE, DELETE)
- flush 실행:
entityManager.flush()
또는 entityManager.commit()
또는 JPQL 쿼리 실행 시
- JPQL 쿼리 실행 시 flush가 실행되는 이유
- 조회할 때 영속성 컨텍스트(1차 캐시)에 저장하려면 id가 필요한데, AUTO_INCREMENT 등을 통해 자동으로 생성하는 경우 DB에서 자동 생성된 id를 가져와야 하기 때문
commit
- DB Commit
- 자동으로 영속성 컨텍스트 flush를 실행한다
- 영속성 컨텍스트를 비우지 않는다
clear
- 영속성 컨텍스트 초기화
entityManager.clear()
close
- 영속성 컨텍스트 소멸
entityManager.close()