EntityManagerFactory
- Client의 요청이 올 때마다 EntityManager를 생성합니다.
EntityManager
- 데이터베이스 Connection을 사용해서 DB 처리를 진행합니다.
Entity의 생명 주기
- 비영속 (new/transient)
- 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
- 영속 (managed)
- 영속성 컨텍스트에 Entity가 관리되는 상태
- EntityManager.persist(entity)
- 아직 DB에 저장되지 않고 이후 transaction을 commit한 후에 DB에 저장됩니다.
- 준영속 (detached)
- 삭제 (removed)
EntityManager em = emf.createEntityManager();
EntiryTransaction tx = em.getTransaction();
tx.begin();
try {
// 객체를 생성한 상태 (비영속)
Member member = new Memb er();
member.setId("member1");
member.setUsername("회원1");
// 객체를 저장한 상태 (영속)
// 지연 SQL 저장소에 저장하고 있다가 transaction commit 시점에 DB INSERT 쿼리가 전달됨
em.persist(member);
// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
// detach를 하면 transaction commit 시점에 DB INSERT 쿼리가 날라가지 않게됨
em.detach(member);
// 객체를 삭제한 상태 (삭제)
em.remove(member);
tx.commit();
} catch(Exception e) {
tx.rollback();
} finally {
em.close();
}
영속성 컨텍스트(환경, 문맥)
- 엔티티를 영구 저장하는 환경 (논리적인 개념)
- EntityManager.persist(entity)
- DB에 저장하는것이 아니라 영속성 컨텍스트에 저장합니다.
- EntityManager는 영속성 컨텍스트를 데이터베이스 Transaction 단위로 만들고 Transaction이 끝나는 시점에 영속성 컨텍스트를 삭제합니다.
- EntityManager를 통해서 영속성 컨텍스트에 접근
- EntityManager를 생성하면 PersistenceContext가 1:1로 생성되어집니다.
- 영속성 컨텍스트가 필요한 이유
- 1차 캐시
- Map 종류의 1차 캐시가 존재하며 Key는 @Id로 설정한 필드의 값이 되고 Value는 해당 엔티티 객체가 됩니다.
- EntityManager를 통해서 조회 요청 시 바로 DB 조회를 시도하는 것이 아니라 1차 캐시에서 값을 조회하고 없을 경우 DB 조회를 시도합니다.
- 1차 캐시에 없는 경우 시나리오
- 1차 캐시를 조회
- 1차 캐시에 없으므로 DB 조회
- DB에서 조회한 데이터를 1차 캐시에 저장
- 반환
- 동일성(identity) 보장
- 같은 Transaction 안에서 동일한 entity를 조회 할 경우 동일성 비교(==)를 했을 때 true를 리턴합니다.
- 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
- EntityManager.persist(entity)를 호출 시점에 쓰기 지연 SQL 저장소에 순서대로 저장하고 있다가 Transaction이 Commit되는 시점에 실제 DB에 INSERT QUERY가 전달되게 됩니다.
- 변경 감지 (Dirty Checking)
- Transaction Commit이 이루어질 때 동작 시나리오 (flush() 가 호출됨)
- 1차 캐시에 있는 엔티티와 스냅샷을 비교
- 변경 된 부분에 대해 UPDATE SQL을 작성하고 쓰기 지연 SQL 저장소에 저장
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송
- 데이터베이스 Commit
- 지연 로딩 (Lazy Loading)
inflearn 강좌 : 자바 ORM 표준 JPA 프로그래밍 - 기본편