문홍의 공부장

[Java JPA] JPA 영속성 컨텍스트 개념 정리 본문

개발/Java

[Java JPA] JPA 영속성 컨텍스트 개념 정리

moonong 2022. 4. 22. 17:17
반응형

JPA 영속성 컨텍스트

  • 영속성: 프로그램이 종료되어도 사라지지 않는 데이터의 특성.
  • 영속성 컨텍스트: 엔티티를 영구 저장하는 환경.

개념

  • 애플리케이션과 데이터베이스 사이에서, 객체를 보관하는 논리적 개념 (가상의 DB 역할)
  • 영속성 컨텍스트는 직접 접근이 불가하며, 엔티티 매니저EntityManager 를 통해서 접근 가능하다.
  • EntityManager를 통해 엔티티를 저장/조회 시, 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다. (em.persist())
  • 트랜잭션을 커밋하는 시점에 영속성 컨텍스트의 내용이 테이블에 반영된다. (em.flush())

엔티티의 생명주기

  • 비영속(new/transient)
    • 엔티티를 생성했지만 아직 영속성 컨텍스트에 저장하지 않은 상태
  • 영속(managed)
    • 엔티티 매니저를 통해 엔티티를 영속성 컨텍스트에 저장한 상태. (em.persist())
    • 영속성 컨텍스트에 의해 관리되며, 아직 DB에 저장되지는 않음.
  • 준영속(detached)
    • 영속성 컨텍스트에 저장되었다가 분리된 상태 (em.detach())
    • 영속성 컨텍스트가 관리하던 영속 상태의 엔티티 더이상 관리하지 않음
  • 삭제(removed)
    • 엔티티를 영속성 컨텍스트와 DB에셔 삭제 (em.remove())

특징

  • 영속 상태는 반드시 식별자 값(@Id)을 지닌다.
  • 트랜잭션 커밋 시 영속성 컨텍스트에 저장된 내용을 데이터베이스에 자동으로 반영(동기화) 한다. (em.flush())

장점

1차 캐시

영속성 컨텍스트 내부에 존재하는 캐시. 영속 상태의 엔티티를 1차 캐시에 저장한다. (key:value = 식별자값:엔티티 인스턴스)

// em.find(엔티티 클래스 타입, 식별자 값);
Member member = em.find(Member.class, "member1");

[조회의 흐름]

  1. 1차 캐시에서 엔티티를 찾는다
  2. 있으면 메모리에 있는 1차 캐시에서 엔티티를 조회한다.
  3. 없으면 데이터베이스에서 조회한다.
  4. 조회한 데이터로 엔티티를 생성해 1차 캐시에 저장한다. (엔티티를 영속상태로 만든다)
  5. 조회한 엔티티를 반환한다.

즉, 영속성 컨텍스트의 1차 캐시에 존재한다면 데이터베이스까지 가지 않고 바로 엔티티를 조회할 수 있다.

동일성 보장

영속성 컨텍스트는 엔티티의 동일성을 보장한다.

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.print(a==b) // true

SQL mapper 를 사용하여 결과를 가져와 객체 a, b 에 담았다면, 두 객체의 주소값이 다르기 때문에 a==b 는 false 가 나왔을 것이다.

하지만 JPA 를 사용할 경우 em.find()를 반복 호출하여도 영속성 컨텍스트의 1차 캐시에 보관된 같은 인스턴스를 반환한다.

이런 이유로 영속 엔티티의 동일성을 보장할 수 있다.

트랙잭션을 지원하는 쓰기 지연

em.persist(member1);
em.persist(member2);

엔티티 매니저는 트랜잭션을 커밋하기 직전까지 내부 쿼리 저장소에 INSERT SQL을 모아두고, 트랜잭션을 커밋할 때 모아둔 쿼리를 DB에 보낸다.

이것을 트랜잭션을 지원하는 쓰기 지연이라 한다.

변경 감지 (Dirty checking)

엔티티를 조회해서 데이터를 변경하면, JPA는 변경 내용을 감지하여 update SQL 를 생성한다.

Member member = em.find(Member.class, 10L);
member.setName("changedName");

transaction.commit(); // execute update query

[변경감지의 흐름]

  1. 트랙잭션을 커밋하면 엔티티 매니저 내부에서 먼저 플러시가 호출된다.
  2. 엔티티와 1차 캐시 내의 스냅샷을 비교하여 변경된 엔티티를 찾는다.
  3. 변경된 엔티티가 있으면 UPDATE SQL 를 생성해서 쓰기 지연 SQL 저장소에 저장한다.
  4. commit 이 되면 쓰기 지연 저장소의 SQL을 플러시한다.

지연 로딩 (Lazy Loading)

연관관계 매핑되어 있는 엔티티 조회 시, 프록시를 반환함으로써 쿼리를 진짜 필요할 때 실행하도록 하는 기능

플러시 (flush) ?

  • 영속성 컨텍스트의 변경 내용을 DB 에 반영

플러시가 발생하면

  • 변경 감지
  • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
  • 쓰기 지연 SQL 저장소의 쿼리를 DB 에 전송

플러시하는 방법

  • 트랜잭션 커밋 시 자동 호출
  • em.flush()
  • JPQL 쿼리 실행

Reference.

  1. https://velog.io/@neptunes032/JPA-영속성-컨텍스트란
  2. https://willseungh0.tistory.com/65
반응형