EntityManagerFactory를 통해 EntityManager를 생성한다.
EntityManager를 통해 Entity를 수정, 삭제, 조회 등을 한다.
EntityManagerFactory는 여러 스레드가 동시에 접근해도 안전
EntityManager는 여러 스레드가 동시에 접근하면 동시성 문제가 발생
EntityManager는 트랜잭션을 시작할 때 DB커넥션을 획득한다.
영속성 컨텍스트는 Entity를 영구 저장하는 환경이라는 뜻.
애플리케이션과 DB사이에서 객체를 보관하는 가상의 DB같은 역할.
EntityManager를 생성할 때 하나 만들어지고, EntityManager를 통해 영속성 컨텍스트에 접근하고 관리할 수 있다.
비영속(new/translent)
엔티티 객체를 생성했지만 아직 영속성 컨텍스트에 저장하지 않은 상태를 비영속(new/transient)라 한다. (순수한 객체 상태)
Member member = new Member();
영속(managed)
EntityManager를 통해 Entity를 영속성 컨텍스트에 저장한 상태.
em.persist(member)
준영속(detached)
영속성 컨텍스트가 관리하던 영속 상태의 Entity를 영속성 컨텍스트가 관리하지 않으면 준영속 상태가 된다.
//회원 엔티티를 영속성 컨텍스트에서 분리
em.detach(member)
//영속성 컨텍스트를 닫는다.
em.close()
//영속성 컨텍스트를 초기화
em.clear()
삭제(removed)
엔티티를 영속성 컨텍스트와 DB에서 삭제
em.remove(member)
1차 캐시
영속성 컨텍스트는 내부에 캐시(1차 캐시)를 갖고있다.
영속상태의 Entity는 이 1차 캐시에 저장된다.
Member member = new Member();
member.setId("member1");
em.persist(member);
1차 캐시의 키는 기본키와 매핑된 @Id 식별자 값이다.
em.find()를 호출하면 식별자 값으로 캐시에서 Entity를 찾고, 없으면 DB에서 조회하고 1차 캐시에 저장한다.
동일성 보장
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a==b) //True
em.find()를 반복 호출해도 영속성 컨텍스트는 1차 캐시에 있는 Entity인스턴스를 반환한다.
즉, 둘은 같은 인스턴스이고 동일성을 보장한다.
public Member memberDAO(String memberId){
String sql = "SELECT * FROM MEMBER WHERE MEMBER_ID=?";
```
return new Member(...);
}
Member a = memberDAO.getMember("member1");
Member b = memberDAO.getMember("member1");
System.out.println(a==b) //False
RDBMS는 기본키가 동일하다면 같은 레코드로 정의한다.
객체에서 동일성은 참조 값을 비교하여 같은 것을 의미한다.
객체와 RDBMS에서 동일성이 다른 의미를 가지는 불일치를 해결한다.
트랜잭션을 지원하는 쓰기 지연
EntityManager는 트랜잭션을 커밋하기 전까지 DB에 Entity를 저장하지 않고 내부 쿼리 저장소에 SQL을 모아둔다.
트랜잭션을 커밋할 때 모아둔 쿼리를 DB에 한번에 보낸다.
SQL을 그때 그때 DB에 바로 보내나, 한번에 모아서 보내나 결국은 commit을 해야 모두 저장되고 rollback을 하면 모두 저장되지 않는다.
즉, commit직전에만 SQL을 전달하면된다. → 쓰기 지연이 가능한 이유.
변경 감지
//영속성 엔티티 조회
Member a = em.find(Member.class, "memberA");
//영속성 엔티티 수정
a.setUsername("aaa");
JPA로 Entity를 수정할 때 단순히 Entity를 조회하고 변경만 하면 된다.
JPA는 Entity를 영속성 컨텍스트에 보관할 때, 최초 상태를 저장한다(스냅샷)
그리고 DB에 저장(플러시)하는 시점에 스냅샷과 Entity를 비교하여 변경된 Entity를 찾는다.
변경된 Entity가 있으면 update쿼리를 생성해 쓰기지연 SQL저장소에 보낸다.
commit을 하면 DB에 SQL을 보내서 update가 된다.
지연 로딩