EntityManager 인스턴스를 생성하는 팩토리 인터페이스로 JPA 구현체(Hibernate 등)에 의해 생성된다.
그림에서도 볼 수 있듯이 이 팩토리를 통해 여러 개의 EntityManager
인스턴스가 생성된다.
엔티티 저장, 조회, 수정, 삭제 등 엔티티에 대한 모든 작업을 수행하는 핵심 객체다.
실제로는 이 EntityManager가 내부적으로 영속성 컨텍스트(Persistence Context)를 관리하고 그 컨텍스트를 통해 엔티티의 상태를 추적한다.
언제 EntityManager와 Persistence Context는 1:1이고, 언제 1:N 관계일까?
Jakarta Persistence 3.2 명세의 '7.1 Persistence Context' 절에 따르면,
EntityManager
는 관리 방식에 따라 크게 두 가지로 나뉜다: 컨테이너 관리형과 애플리케이션 관리형.컨테이너 관리형(Container-managed EntityManager)
대상 환경: Jakarta EE 환경
Jakarta EE 애플리케이션에서는
@PersistenceContext
를 통해EntityManager
를 의존성 주입받는다. 이 경우, 트랜잭션 범위에 따라 하나의 영속성 컨텍스트가 여러 컴포넌트에 주입된EntityManager
인스턴스에 의해 공유된다.
즉, 하나의 Persistence Context가 여러 컴포넌트에 주입된 EntityManager 인스턴스 간에 공유되므로 1:N 관계가 성립할 수 있다.@PersistenceContext private EntityManager entityManager;
애플리케이션 관리형(Application-managed EntityManager)
대상 환경: Java SE, Jakarta EE Application Client(Container) 또는 독립형 Jakarta EE 컴포넌트
이 경우
EntityManagerFactory
를 통해 개발자가 명시적으로EntityManager
를 생성하고 생명주기를 직접 관리한다. 이렇게 생성된EntityManager
는 각기 고유한Persistence Context
를 갖기 때문에 EntityManager와 Persistence Context는 1:1 관계로 유지된다.EntityManagerFactory emf = Persistence.createEntityManagerFactory("unitName"); EntityManager em = emf.createEntityManager();
요약하면 Jakarta EE 환경에서는 트랜잭션 범위 내에서 하나의 Persistence Context를 여러 컴포넌트 간 공유하는 1:N 구조가 가능하지만 Java SE 및 Application Client 환경에서는 항상 1:1 관계만 허용된다.
엔티티를 영구 저장하는 환경 또는 엔티티 객체들을 관리하는 메모리 상의 저장소이다. 이는 애플리케이션과 데이터베이스 사이에서 엔티티 객체를 관리하며 엔티티의 상태를 추적하고 변경 사항을 감지하여 데이터베이스에 반영하는 역할을 합니다.
엔티티에는 4가지 상태가 존재한다.
new
키워드로 객체를 생성했지만 아직 EntityManager.persist()
를 호출하지 않은 상태이다. 영속성 컨텍스트에 등록되지 않았기 때문에 아무런 DB 작업도 발생하지 않는다.
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager.persist(member)
를 호출하면 해당 객체는 영속성 컨텍스트에 저장된다. 이제부터는 JPA가 해당 엔티티의 상태 변화를 추적하며 트랜잭션 커밋 시 자동으로 DB 반영이 된다. 1차 캐시에 등록되며 동일 ID로 조회하면 항상 같은 객체 반환된다.
em.persist(member);
엔티티는 영속성 컨텍스트에서 분리되며 더 이상 상태 변화가 감지되지 않는다.
em.detach(entity)
em.clear()
따라서 준영속 상태의 엔티티는 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.
em.detach(member);
member.setUsername("변경된 이름"); // 반영되지 않음, 커밋해도 UPDATE 쿼리 X
EntityManager.remove(entity)
를 호출하면 해당 엔티티는 삭제 예약 상태로 전환된다. 실제 DB에서 삭제되는 시점은 flush()
가 호출되거나 트랜잭션이 커밋될 때이다.
em.remove(member);
참고