EntityManagerFactory와 EntityManager
EntityManagerFactory
- EntityManager를 만들어내는 곳.
- 생성 비용이 크므로 애플리케이션 전체에서 딱 한번만 생성하고 공유해서 사용해야 한다.
EntityManager
- EntityManager를 이용해 DB와 Connection을 유지하여 CRUD를 한다.
- EntityManagerFactory를 통해 생성되며 비용이 거의 들지 않는다.
- 스레드 간에 공유하거나 재사용하면 안 된다.
public void createMember() {
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Member member = new Member("name", "age");
em.persist(member);
transaction.commit();
}
관계도
- EntityManager는 DB 연결이 필요한 시점에 Connection을 얻는다.
ex) 트랜잭션이 시작할 때. - JPA의 구현체들은 EntityManagerFactory를 생성할 때 커넥션풀을 만든다.
영속성 컨텍스트
정의
- 엔티티를 영구 저장하는 환경.
- EntityManager로 엔티티를 저장하거나 조회하면 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
EntityManager와 관계
- 기본적으로 EntityManager를 생성할 때 하나 만들어진다.
- 하지만 컨테이너 환경의 JPA에서는 여러 EntityManager가 하나의 영속성 컨텍스트를 공유한다.
- 이는 아래 ‘트랜잭션 범위의 영속성 컨텍스트’에서 살펴본다.
컨테이너 환경에서 JPA
- 컨테이너를 사용하는 환경(ex. Spring)에서는 개발자가 EntityManager를 직접 생성하지 않고 생성을 컨테이너에 위임한다.
스프링이 관리하는 EntityManager의 Thread-Safe를 어떻게 보장할까?
- 결론부터 말하면 EntityManager를 Proxy를 통해 감싸고 EntityManager를 사용할 때 Proxy를 통해 EntityManager를 생성한다.
- EntityManger를 직접 사용하는 경우 @PersistenceContext를 사용하면 된다.
확인 1 : 직접 생성한 EntityManager에 @PersistenceContext 선언
entityManager = {$Proxy84@9656} "Shared EntityManager proxy for target factory [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@4f356b98]"
- SharedEntityManagerCreator에 의해 Proxy로 만들어진다.
확인 2 : SimpleJpaRepository의 EntityManager
em = {$Proxy84@9748} "Shared EntityManager proxy for target factory [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@4f356b98]"
- SharedEntityManagerCreator에 의해 Proxy로 만들어진다.
트랜잭션 범위의 영속성 컨텍스트
- 스프링 컨테이너는 트랜잭션 범위의 영속성 컨텍스트 전략을 기본으로 사용한다.
- 트랜잭션이 시작할 때 영속성 컨텍스트를 생성하고 트랜잭션이 끝날 때 영속성 컨텍스트를 끝낸다.
트랜잭션이 같으면 같은 영속성 컨텍스트를 사용한다
- 여러 EntityManager를 사용해도 한 트랜잭션으로 묶이면 영속성 컨텍스트를 공유한다.
트랜잭션이 다르면 다른 영속성 컨텍스트를 사용한다
- 같은 EntityManager를 사용해도 트랜잭션에 따라 접근하는 영속성 컨텍스트가 다르다.
- 따라서 같은 EntityManager를 호출해도 접근하는 영속성 컨텍스트가 다르므로 멀티스레드에 안전하다.