EntityManagerFactory
Entity를 관리하는 EntityManager를 생산하는 공장
요청당 1개의 EntityManager 생성
생성 비용이 크기 때문에 Application 로딩 시점에 생성해 EntityManager들간 공유하도록 설계
Thread Safe
EntityManager
JPA를 이용하는데 가장 중요한 요소
Entity를 영구 저장하는 환경
EntityManager는 Entity를 영속성 컨텍스트에 보관하고 관리
persist()를 통해 Entity가 영속성 컨텍스트로 들어감
특징
LifeCycle
비영속(new/transient) : 영속성 컨텍스트와 전혀 관계가 업는 상태
영속(managed) : 영속성 컨텍스트에 저장된 상태
- persist() : 비영속->영속
준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
삭제(removed) : 삭제된 상태
비영속 : 객체가 영속성 컨텍스트, DB와 무관한 상태
Customer customer = new Customer();
customer.setId(1L);
customer.setFirstName("dsf)";
customer.setLastName("park");
영속
Customer customer = new Customer();
customer.setId(1L);
customer.setFirstName("dsf)";
customer.setLastName("park");
// 객체를 영속성 컨텍스트에서 관리
em.persist(customer);
준영속
// 영속상태의 entity를 영속성 컨텍스트에서 분리
em.detach(customer);
// 영속상태의 모든 객체를 영속성 컨텍스트에서 분리
em.clear();
// 영속성 컨텍스트 종료
em.close();
삭제
// customer Entity를 영속성 컨텍스트에서 분리하고, DB에서도 삭제
em.remove(customer)
EntityManager em = emf.createEntityManager(); //1) entityManager 생성
EntityTransaction transaction = em.getTransaction(); // 2) 트랜잭션 획득
transaction.begin(); //3) 트랜잭션 begin
Customer customer = new Custoemr(); //4-1) 비영속 상태
customer.setId(1L);
customer.setFirstName("asdf");
customer.setLastName("Park");
em.persist(customer); //4-2) 영속화
// 1차 캐시와 쓰기지연저장소에 등록됨
transaction.commit(); // 5) 트랜잭션 commit
// 트랜잭션이 커밋되는 순간 쿼리가 수행됨. flush되며 DB와 동기화됨
조회
1) 1차 캐시를 이용한 조회
@Test
void 조회_1차캐시_이용(){
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Custoemr();
customer.setId(1L);
customer.setFirstName("asdf");
customer.setLastName("Park");
em.persist(customer);
transaction.commit();
Customer entity = em.find(Customer.class, 1L); // 1차 캐시에서 조회
log.info("{} {}", entity.getFirstName(), entity.getLastName());
}
1차캐시에 있으면(em.find()) DB에 쿼리를 날지지 않고, 1차캐시에서 조회
2) DB를 이용한 조회
@Test
void 조회_1차캐시_이용(){
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Custoemr();
customer.setId(1L);
customer.setFirstName("asdf");
customer.setLastName("Park");
em.persist(customer);
transaction.commit();
em.clear(); // 영속성 컨텍스트 초기화(모든 entity 준영속, 쓰기저장지연소 초기화)
Customer entity = em.find(Customer.class, 1L); // 1차캐시에 데이터 없음. DB 조회하여 1차캐시에 캐싱.
log.info("{} {}", entity.getFirstName(), entity.getLastName());
em.find(Customer.class, 1L); // 캐싱된 1차캐시 사용
}
Entity가 준영속화되어 1차캐시에 없으면 DB조회후 Entity 만들어 1차캐시에 삽입.
이후 요청은 1차캐시에 조회 후 반환됨
수정
@Test
void 수정(){
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Custoemr();
customer.setId(1L);
customer.setFirstName("asdf");
customer.setLastName("Park");
em.persist(customer);
transaction.commit();
transaction.begin();
Customer entity = em.find(Customer.class, 1L);
entity.setFirstName("sdf");
entity.setLastName("Kim");
//em.update(entity);
transaction.commit();
}
persist(entity)로 영속화된 Entity는 최소 영속화 시점의 상태가 스냅샷으로 기록되어, commit시 스냅샷과 현재 Entity를 비교해 변경된 Entity의 update 쿼리가 쓰기지연저장소에 저장됨. 이후 쓰기저장지연소의 쿼리문을 flush하여 DB 반영
삭제
@Test
void 삭제(){
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin();
Customer customer = new Custoemr();
customer.setId(1L);
customer.setFirstName("asdf");
customer.setLastName("Park");
em.persist(customer);
transaction.commit();
transaction.begin();
Customer entity = em.find(Customer.class, 1L);
em.remove(entity);
transaction.commit(); //flush -> DETELT 쿼리
}
Entity가 영속상태에 있으면 조회시 1차캐시로(쿼리 X)
준영속상태(/비영속상태라면?) DB SELECT 쿼리 실행하여 Entity를 만들고 1차캐시에 저장,
1차캐시의 Entity 반환.
이후 질의에서는 1차캐시의 Entity반환
Dirty check : 최초 영속상태로 등록될때의 스냅샷과 비교하여 최종 tranaction Commit(flush) 직전에 변경된 내용이 있다면 UPDATE 쿼리 생성
영속성컨텍스트에서 관리하는 Entity에만 해당됨