영속성 컨텍스트

SeungHoon·2024년 6월 20일

Spring

목록 보기
4/15

엔티티 매니저

@Entity 어노테이션을 달고 있는 Entity 객체들을 관리하며 실제 DB 테이블과 매핑하여 데이터를 조회/수정/저장 하는 중요한 기능을 수행한다. EntityManager는 PersistenceContext라는 논리적 영역을 두어, 내부적으로 Entity의 생애주기를 관리한다.

영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경이라는 뜻이다.
  • 애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스 역할을 한다.
  • 엔티티 매니저를 통해 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
  • em.persist(member); : 엔티티 매니저를 사용해 회원 엔티티를 영속성 컨텍스트에 저장한다는 의미이다.
  • 영속성 컨텍스트의 특징
    • 엔티티 매니저로 생성할 때 하나 만들어진다. (싱글톤)
    • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근하고 관리할 수 있다.
    • 영속성 컨텍스트는 동일한 Transaction 내에서 모든 객체들을 관리한다.

엔티티의 생명주기

  • 비영속 : 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 영속 : 영속성 컨텍스트에 저장된 상태
  • 준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제 : 삭제된 상태

코드와 함께 보기

  • 비영속 : 엔티티 객체를 생성했으나 아직 영속성 컨텍스트에 저장하지 않은 상태
Member member = new Member();
  • 영속 : 엔티티 매니저를 통해서 영속성 컨텍스트에 저장한 상태를 말하며 영속성 컨텍스트에 의해 엔티티가 관리됨.
em.persist(member);
  • 준영속 : 더 이상 영속성 컨텍스트가 관리하지 않으면 준영속 상태가 된다.
    • 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다.
    • 식별자 값을 가지고 있다.
// 엔티티를 영속성 컨텍스트에서 분리해 준영속 상태로 만든다.
em.detach(member);
// 영속성 콘텍스트를 비워도 관리되던 엔티티는 준영속 상태가 된다.
em.claer();
// 영속성 콘텍스트를 종료해도 관리되던 엔티티는 준영속 상태가 된다.
em.close();
  • 삭제 : 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.
em.remove(member);

참고로 "삭제"의 경우 영속성 컨텍스트에서는 제거되지만 Java 입장에서 GC의 대상이 되는 것은 아니다.

영속성 컨텍스트의 특징

  • 영속성 컨텍스트의 식별자 값
    • 영속성 컨텍스트는 엔티티를 식별자 값으로 구분한다. 따라서 영속 상태는 식별자 값이 반드시 있어야 한다.
  • 영속성 컨텍스트와 데이터베이스 저장
    • jpa는 보통 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 데이터베이스에 반영하는데 이를 Flush라고 한다.

영속성 컨텍스트가 엔티티를 관리하면…

  1. 1차 캐시→ DB에 접근할 필요가 없다.

    • 영속성 컨텍스트 내부에는 1차 캐시가 존재하는데, 영속 상태의 엔티티를 여기에 저장한다. 1차 캐시의 키는 식별자 값(데이터베이스의 기본 값)이고 값은 엔티티 인스턴스이다. 다음과 같이 조회한다.
    // em.find(엔티티 클래스 타입, 식별자 값);
    Member member = em.find(Member.class, "member1");
  2. 동일성 보장

    • 싱글톤을 보장한다.
    Member a = em.find(Member.class, "member1");
    Member b = em.find(Member.class, "member1");
    System.out.print(a==b) // true

    참고로 ==가 성립하려면 주소값까지 같아야 함.

  3. 트랜잭션을 지원하는 쓰기 지연

    • 바로바로 SQL문이 발생하지 않고 엔티티 매니저는 트랜잭션을 커밋하기 직전까지 내부 쿼리 저장소에 SQL문을 저장하고 커밋할 때 DB 한번에 전송한다.
  4. 변경 감지

    • jpa로 엔티티를 수정할 때는 단순히 엔티티를 조회해서 값을 변경해주기만 하면 된다. 따로 저장할 필요가 없다. 어떻게 이게 가능하나?
    • 변경 감지의 흐름?
      1. 트랜잭션을 커밋하면 엔티티 매니저 내부에서 flush가 호출된다
      2. 엔티티와 스냅샷을 비교하여 변경된 엔티티를 찾는다
      3. 변경된 엔티티가 있으면 수정 쿼리를 생성하여 쓰기 지연 SQL 저장소(Action Queue)에 저장한다
      4. 쓰기 지연 저장소의 SQL을 flush한다
      5. 데이터베이스 트랜잭션을 커밋한다.
    • 물론 당연히 영속된 엔티티만 변경 감지가 가능하다.

Flush

영속성 컨텍스트의 변경 내용을 DB에 반영한다. (DB와 동기화한다.)

  • Flush 하는 방법
    • em.flush()
    • 트랜잭션 커밋 시 자동호출
    • JPQL 쿼리 발생 시 자동호출
profile
공유하며 성장하는 Spring 백엔드 취준생입니다

0개의 댓글