영속성 컨텍스트(Persistence Context) : 애플리케이션과 테이터베이스 사이에 위치한 가상의 데이터베이스
HashMap
으로 구성되어 key=value : id=Entity 로 돌아간다.EntityManagerFactory : EntityManager 를 생성한다.
EntityManager : 영속성 컨텍스트(가상 데이터베이스)를 관리하는 객체
EntityManager
를 생성해야 한다.DataSource
와 매핑된 Persistence
에서 connection
을 가져온다EntityManagerFactory
는 EntityManager
를 생성하고 EntityManager
는 connection
을 Lazy
로 가지게 된다.EntityManager
가 생성되면 매핑된 EntityManagerFactory
에서 connection
을 얻지만 connection
이 꼭 필요한 시점 flush
메서드가 호출되는 시점에서 connection
을 사용한다.EntityManager
는 EntityTransaction
객체를 생성해 transaction
을 시작하며 connection
을 연결한다.EntitTransaction
을 폐기하며 transaction
을 종료하고 EntityManager
을 폐기한다.EntityManager
는 Thread-Safe
하지 않기 떄문에 매 작업마다 인스턴스를 새로 생성한다.EntityManagerFactory emf = Persistence.createEntityManagerFactory("test"); // emf 생성
EntityManager em = emf.createEntityManager(); // em 생성
EntityTransaction tx = em.getTransaction(); // 트랜잭션 획득
try{
tx.begin(); // 트랜잭션 시작
biz_logic(em); // 비즈니스 로직 실행
tx.commit(); // 트랜잭션 커밋
} catch (Exception e) {
tx.rollback(); // 오류 시 롤백
} finally {
em.close(); // em 종료
}
emf.close(); // emf 종료
영속성 컨텍스트 : 단순히 Entity
의 집합니다. 이 안에서 모든 Entity
인스턴스의 생명주기가 관리되며, EntityManager
의 모든 public API(findById
, flush
등) 들은 이 생명주기를 관리하는데 쓰인다. HashMap
으로 Entity
들을 가지고 있다. 따라서 DB
의 PK
와 바로 연결하지 않고 연속성 컨텍스트 내부에서 HashMap
으로 key
와 entity
를 매핑함으로써 connection
을 줄여 DB 부하를 줄인다. 그 후 flush
를 통해 영속성 컨텍스트 내부의 데이터를 한꺼번에 db 에 반영한다.
영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
Member member = new Member();
영속성 컨텍스트에 관리되는 상태
em.persist(member);
entity manager. persist 하면 영속 상태로(managed)
영속성 컨텍스트에 저장되었다가 분리된 상태, 더이상 영속 상태의 엔티티가 아니다.
detach
하면 다시 영속성 컨텍스트와 관련이 없어진다.
em.detach(member); // 엔티티를 영속성 컨텍스트에서 분리
em.claer(); // 영속성 콘텍스트를 비움
em.close(); // 영속성 콘텍스트를 종료
비영속 상태는 식별자가 있을수도 있고, 없을 수도 있다.
하지만 준영속 상태의 경우 식별자가 반드시 존재한다.
- 비영속 상태에는
entity
객체 생성 시id
를 초기화 하지 않았으므로 식별자가 없다.- 만약 개발자가 초기
entity
객체 생성 시 직접 id 를 초기화해 생성하면EntityManage
는 비영속이 아닌 준영속 상태로 간주한다.- 즉 준영속 상태는 내부
HashMap
에 같은 식별자를 갖는Entity
가 존재하지 않지만,Entity
에는 식별자가 있는 모든 경우를 의미한다.
**- 이런 경우persist
뿐만 아니라merge
메서드도 가능하다(비영속임에도 불구하고)
엔티티가 영속성 컨텍스트와 db 에서 삭제되도록 예약된 상태 최종적으로 모두 삭제된다.
em.remove(member);
flush
호출시 영속성 컨텍스트에서 제거됨과 동시에 db 에 delete 쿼리가 발생한다.flush
라고 한다.영속 상태의 Entity
는 모두 영속성 컨텍스트에 HashMap(key(@Id) = value(Entity))
로 저장된다.
따라서 식별자(@Id)
가 반드시 있어야 한다.
Member member = new Member();
member.setId("member1"); // 직접 id 값을 초기화 암으로써 준영속상태로 인지한다.
member.seUsername("회원1");
// 엔티티 영속(1차 캐시 저장)
em.persist(member);
// 1차 캐시에서 조회
em.find(Member.class, "member1");
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // true 반환
em.update
와 같은 코드를 작성하지 않는다.
플러시는 영속성 컨텍스트의 변경 내용을 db 에 반영한다. 즉 변경 내용을 db 와 동기화 하는 것이다.
플러시하는 방법
1.em.flush()
2. 트랜잭션 commit 시 자동 호출
3. JPQL 쿼리 실행 시 자동 호출
https://velog.io/@neptunes032/JPA-%EC%98%81%EC%86%8D%EC%84%B1-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EB%9E%80
심화내용까지 보고싶으면 참고해 보세요 : https://shirohoo.github.io/spring/spring-data-jpa/2021-06-23-jpa-3/