JPA에서 가장 중요한 2가지
- 객체와 관계형 데이터베이스 매핑하기
- 영속성 컨텍스트
영속성 컨텍스트
- JPA를 이해하는데 가장 중요한 용어
- “엔티티를 영구 저장하는 환경”이라는 뜻
- 논리적인 개념
- 눈에 보이지 않는다.
- 엔티티 매니저를 통해서 영속성 컨텍스트에 접근한다.
엔티티의 생명주기
- 비영속(new/transient)
- 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
- 영속(managed)
- 영속성 컨텍스트에 관리되는 상태
- 준영속(detached)
- 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제(removed)
- 삭제된 상태
Code
영속된다고 해서 DB에 저장되는 것이 아니라.
commit을 할 때 저장이 된다.
영속성 컨텍스트의 장점
- 1차 캐시
- 동일성(identity)보장
- 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
- 변경 감지(Dirty Checking)
- 지연로딩(Lazy Loading)
1차캐시 이점
1차캐시에서 조회
내부에는 1차 캐시가 있는데 Key와 객체 자체가 Entity가 된다.
데이터베이스에서 조회
1차캐시에서 찾아봤는데 없으면 DB에 조회를 한 후 1차캐시에서 저장한 다음 캐시에서 반환을 한다.
영속 엔티티의 동일성 보장
//영속
Member findMember1 = em.find(Member.class, 101L);
Member findMember2 = em.find(Member.class, 101L);
System.out.println("result = " + (findMember1 == findMember2));
//결과
result = true
1차 캐시로 반복 가능한 읽기 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공
엔티티 등록 트랜잭션을 지원하는 쓰기 지연
영속성 컨텍스트 안에는 쓰기 지연 SQL 저장소가 존재하는데 memberA에 대해서 INSERT문을 생성해두고 그러면서 1차 캐시에 저장한다.
memberB에 대해서도 똑같이 저장되는데 1차 캐시에 이전에 실행한 memberA가 있는 것을 확인할 수 있다.
저장이 되는 것은 commit(); 을 통해 진행되는데 이때 DB에 실질적으로 INSERT문이 실행된다.
엔티티 수정 - 변경 감지
다음과 같은 코드로 member의 DB의 이름이 변경된다.
//영속
Member member = em.find(Member.class, 150L);
member.setName("ZZZZ");
tx.commit();
아래와 같은 메커니즘이 있다.
1차 캐시에 스냅샷에 memberA스냅샷과 비교하며 UPDATE문을 쓰기 지연 SQL 저장소에 저장해두고 commit을 날리면 UPDATE문이 반영이 된다.
플러시
영속성 컨텍스트의 변경내용을 데이터베이스에 반영
플러시가 발생하면?
- 변경 감지
- 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송(등록, 수정, 삭제 쿼리)
영속성 컨텍스트를 플러시하는 방법
- flush() - 직접 호출
- 트랜잭션 커밋 - 플러시 자동 호출
- JPQL 쿼리 실행 - 플러시 자동 호출
//영속
Member member = new Member(200L, "memeber200");
em.persist(member);
em.flush();//강제호출
System.out.println("====================");
//결과
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
====================
위와 같이 결과를 직접 호출을 통해 쿼리문을 확인할 수 있다.
주의: 1차 캐시는 지워지지않는다
결론
- 쓰기지연 SQL 저장소에 있는 쿼리문들을 DB에 반영한다.
- 영속성 컨텍스트를 비우지 않는다
- 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화
- 트랜잭션이라는 작업 단위가 중요하다 → 커밋 직전에만 동기화 하면 된다.
준영속 상태
- 영속 → 준영속
- 영속 상태의 엔티티가 영속성 컨텍스트에서 분리되는 것
- 영속성 컨텍스트가 제공하는 기능을 사용 못함
준영속 상태로 만드는 방법
Member member = em.find(Member.class, 150L); //영속 상태
member.setName("AAAAA"); //업데이트 상태
em.detach(member);//준영속 상태
em.clear();//영속성 컨텍스트 전체 초기화
em.close();//영속성 컨텍스트 종료
출처: 인프런 - 자바 ORM 표준 JPA 프로그래밍 - 기본편 김영한