EntityManager는 Entity 의 생명주기를 관리하며, 쿼리를 실행하는 등의 기능을 담당합니다. 이 때, 영속성 컨텍스트라는 공간을 통해 이러한 기능을 지원하게 됩니다.
영속성 컨텍스트
영속성 컨텍스트란, Entity를 저장하고 관리하기 위한 논리적인 공간입니다.
Entity 의 생명 주기 - 상태
비영속
영속성 컨텍스트 에 저장되어있지 않으며, 저장되었던 적이 없는 상태를 의미합니다. 즉, 영속성 컨텍스트와 전혀 무관한 상태를 의미합니다.
영속
현재 영속성 컨텍스트에서 관리되고 있는 상태를 의미합니다.
준영속
이전에 관리를 받았지만, 잠시 관리를 벗어난 상태를 의미합니다.
삭제
영속성 컨텍스트에서 제거된 상태를 의미합니다.
EntityManager 의 메서드를 통한 Entity 의 상태 관리
김영한 저 - 자바 ORM 표준 JPA 프로그래밍 / 기본편 강의 - 인프런
참고
em.merge() 는 비영속 상태나 준영속 상태인 Entity 를 영속성 컨텍스트의 관리를 받도록 하는 메서드 입니다. 이 때, 기본적으로 준영속 상태, 즉, 이미 저장되었던 Entity 를 다시 저장하는 것이기 때문에 기본 동작에 주의해야 합니다.
기본 동작 과정은 다음과 같습니다. 먼저, 해당 Entity 의 id 필드를 확인하여 준영속 상태인지, 비영속 상태인지 확인합니다.
해당 Entity 가 준영속 상태인 경우, 영속성 컨텍스트의 관리를 받지 않는 동안에 데이터베이스에서 변경이 있을 수 있기 때문에 EntityManager 는 데이터베이스에서 조회 합니다. 만약 데이터베이스가 존재하는 경우, 해당 데이터를 기준으로 새로운 인스턴스를 만들어 저장후에 반환합니다. 존재하지 않는다면 새로운 인스턴스를 생성 후 영속화시킵니다.
만약 해당 Entity 가 비영속 상태인 경우, persist() 와 마찬가지로 새로운 인스턴스를 생성 후 영속화 시킵니다.
영속성 컨텍스트의 기능
1차 캐시
영속성 컨텍스트는 기본적으로 Entity 를 저장하는 공간인 1차 캐시가 존재합니다. 새로운 Entity 를 포함하여, 데이터베이스에서 조회한 Entity 는 식별자와 참조값을 key - value 형태로 저장하며, 이는 데이터베이스에서 여러 번 조회시 데이터베이스에서 직접 조회하고 영속화시키는 것이 아닌 1차 캐시에 저장된 Entity 를 조회하도록 하여 성능에 도움을 줄 수 있도록 합니다. 이는 마치 애플리케이션 레벨에서 Repeatable read 수준의 격리 수준과 비슷하게 동작하도록 도와줍니다.
또한, 같은 식별자를 가진 Entity 는 영속성 컨텍스트 내부에서 하나만 존재하므로, 여러 번 조회하여도 인스턴스의 동일성을 보장할 수 있습니다.
쓰기 지연 SQL 저장소
영속성 컨텍스트에서는 Entity 에 대한 저장이나 수정이 필요할 경우 일반적으로 즉시 쿼리를 전달하지 않습니다. 쓰기 지연 SQL 저장소라는 곳을 통해 쿼리를 모아두고, flush() 메서드 호출시 데이터베이스에 쿼리를 전달하게 됩니다. 사실상 데이터베이스의 입장에서는 매번 쿼리를 받고, 커밋될 때 반영하는 것이나 쿼리를 한 번에 받고 커밋될 때 반영하는 것이나 동일하게 동작하기 때문에 성능적으로 이득인 방법을 지원한다고 볼 수 있습니다.
변경 감지
영속성 컨텍스트는 기본적으로 Entity 영속화시, 초기 상태인 스냅샷을 저장합니다. 이후 트랜잭션 커밋 시점에 스냅샷의 상태와 현재 상태를 비교하여 변경이 있음을 감지하고, 쓰기 지연 SQL 저장소에 update 쿼리를 저장하게 됩니다.