엔티티 매니저 = 엔티티를 저장하는 가상의 데이터베이스
// 공장 만들기, 비용이 아주 많이 듦.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
// 공장에서 엔티티 매니저 생성, 비용이 거의 안 듦.
EntityManager em = emf.createEntityManager();
영속성 컨텍스트(persistence context) = 엔티티를 영구 저장하는 환경
- 영속성 컨텍스트는 엔티티 매니저를 생성할 때 하나 만들어짐.
- 엔티티 매니저를 통해서 영속성 컨텍스트에 접근할 수 있고, 영속성 컨텍스트를 관리할 수 있음.
- 영속성 컨텍스트나 데이터베이스와 전혀 관계가 없는 상태
- 순수한 객체 상태
// 객체를 생성한 상태(비영속) Member member = new Member(); member.setId("member1"); member.setUsername("회원1");
- 영속성 컨텍스트가 관리하는 엔티티
- em.find()나 JPQL을 사용해서 조회한 엔티티도 영속성 컨텍스트가 관리하는 영속 상태
// 객체를 저장한 상태(영속) em.persist(member);
- 영속성 컨텍스트에 저장되었다가 분리된 상태
- em.detach()
- em.clear()
- em.close()
// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태 em.detach(member);
- 삭제된 상태
// 객체를 삭제한 상태(삭제) em.remove(member)
- 영속성 컨텍스트와 식별자 값
- 영속 상태는 식별자 값이 반드시 있어야 함
- 영속성 컨텍스트와 데이터베이스 저장
- JPA는 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영(flush)
- 영속성 컨텍스트가 엔티티를 관리하는 것의 장점
- 1차 캐시
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
1차 캐시: 영속성 컨텍스트 내부에 있는 캐시
영속성 컨텍스트에 데이터를 저장하고 조회하는 모든 기준은 데이터베이스 기본 키 값
em.find()를 호출하면 1차 캐시에서 엔티티를 찾고 만약 찾는 엔티티가 1차 캐시에 없으면 데이터베이스 조회 후 엔티티를 생성해서 1차 캐시에 저장(영속 상태)
영속성 엔티티의 동일성 보장
영속성 컨텍스트는 성능상 이점과 엔티티의 동일성 보장
트랜잭션 커밋 ➡️ 영속성 컨텍스트 플러시 ➡️ 실제 데이터베이스 트랜잭션 커밋
SQL을 사용해서 수정 쿼리를 직접 작성하면 프로젝트가 커지면서 수정 쿼리가 많아지는 것은 물론이고 비즈니스 로직을 분석하기 위해 SQL을 계속 확인해야 함(비즈니스 로직이 SQL에 의존)
변경 감지(dirty checking)
em.remove() ➡️ 트랜잭션 커밋 ➡️ 플러시 ➡️ 실제 데이터베이스에 삭제 쿼리 전달
플러시(flush()) = 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영
- 엔티티 매니저의 flush() 메소드를 직접 호출해서 영속성 컨텍스트를 강제로 플러시
- 트랜잭션을 커밋하기 전에 꼭 플러시를 호출해서 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영해야 하기 때문에 JPA는 트랜잭션을 커밋할 때 플러시를 자동을 호출
- JPQL은 SQL로 변환되어 데이터베이스에서 엔티티를 조회하는데 쿼리 실행 직전에 영속성 컨텍스트를 플러시해서 변경 내용을 데이터베이스에 반영해야 하기 때문에 JPQL을 실행할 때 플러시 자동 호출
준영속 상태 = 영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 것
- 특정 엔티티만 준영속 상태로 전환
- 이 메소드를 호출하는 순간 1차 캐시부터 쓰기 지연 SQL 저장소까지 해당 엔티티를 관리하기 위한 모든 정보 제거됨.
- 영속성 컨텍스트를 완전히 초기화
- 해당 영속성 컨텍스트의 모든 엔티티를 준영속 상태로 만듦.
- 영속성 컨텍스트 종료
merge(): 준영속 상태의 엔티티를 받아서 그 정보로 새로운 영속 상태의 엔티티 반환
병합 = save or update