jpa persistence context

한윤재·2024년 4월 21일

persistence context

1. 소개
2. 특징

소개

jpa의 EntityManager가 Entity객체를 생성 조회 삭제 수정하기 위한 논리적인 공간의 개념이다.

  • Entity란 JPA의 관리 대상 객체로 데이터베이스의 테이블과 그 값이 매핑되어있는 객체를 의미합니다.
  • @Entity 어노테이션을 클래스 선언부에 적으면 JPA가 관리하는 객체로 지정됩니다.

EntityManager란?

엔티티를 관리하는 관리자 객체입니다. 데이터베이스 테이블과 매핑된 자바의 객체를(Entity) Persistence Context에 담아 관리합니다.
이밖에도 트랜잭션, 쿼리객체 생성, DB로 쿼리내보내기 등 다양한 역할을 종합적으로 수행하는 객체입니다.

Persistence Context (영속성 컨텍스트)

Context는 무언가를 담아서 관리하기 위한 공간이라는 뜻으로 주로 사용됩니다. 때로는 컨테이너라고 표현되기도 하며, 이는 조금 비약해서 Map이라고 생각하면 이해하기가 쉬워집니다.

엔티티 매니저가 엔티티를 담아서 관리하는 논리적인 공간이다.

저만의 방식으로 이해하기는 가상의 데이터베이스를 자바 어플리케이션 영역에 정의한 것으로 보입니다.
자바 어플리케이션은 Persistence Context를 객체를 담기위해 만들어진 데이터베이스라고 생각하고, 주로 persistence context 와 소통하면 됩니다.

Persistence Context는 데이터베이스를 한층 추상화시킨 공간으로 이해할 수 있습니다. 자바의 객체가 구체적인 RDB를 고려할 필요없이 이곳에 저장되기만 하면 JPA의 엔티티매니저가 이를 테이블에 맞춰 저장해주고 원할때 객체로서 꺼내주는 방식으로 동작합니다.

의도는 그런 것 같지만. 정확한 매핑을 위해 클래스에 테이블의 명세가 포함됩니다.

자바 어플리케이션 - 엔티티매니저 - Persistence Context - 실제 RDB
자바 어플리케이션이 객체의 CRUD(생성조회수정삭제)를 엔티티 매니저에게 요청하면 엔티티 매니저는 Persistence Context를 작업공간으로 활용해 이곳에서 객체를 관리하고 DB로 내보내거나 가져오기등을 수행합니다.

특징

RDB와 분리된 자바안의 공간에서 가상의 객체 저장소를 제공해주다보니 다음과 같은 특징들을 제공할 수 있습니다.

  • 객체의 1차 캐싱
  • 객체 참조 동일성 보장
  • 쿼리 쓰기 지연
  • 객체 변경 감지
  • 포함 관계의 객체를 지연 로딩

1차 캐싱

객체를 담아놓고 재사용한다.

짧은 설명

EntityManager에게 특정 객체의 조회를 요청합니다. 엔티티매니저는 영속성 컨텍스트에서 객체를 찾고, 없으면 DB에서 데이터를 가져와 객체로 만들어 저장합니다. 동일 객체의 조회를 다시 요청하면 이곳에 저장되어있는 객체를 전달합니다.

긴 설명

엔티티 매니저는 객체를 Persistence Context 에 담아 보관합니다. 엔티티 아이디로 식별된 유일한 엔티티 객체는 영속성 컨텍스트에 단 하나만 담길 것을 보장합니다. 이런 특징으로 엔티티매니저는 DB에서 가져온 객체를 영속성 컨텍스트에 보관하며, 한번 영속성 컨텍스트에 보관된 객체를 자바 어플리케이션이 조회를 요청할때 이곳에 저장(캐싱) 되어있는 객체를 제공하게 됩니다.

동일성 보장

엔티티 아이디로 식별된 유일한 엔티티 객체는 영속성 컨텍스트에 단 하나의 인스턴스만을 보관합니다.

엔티티 매니저에게 동일한 엔티티id 로 조회를 요청한 객체에 대해서 늘 하나의 인스턴스임을 보장합니다.

학생 학생1 = 엔티티매니저.주세요(id=1 , 학생타입);
학생 학생2 = 엔티티매니저.주세요(id=1 , 학생타입);

학생1 == 학생2 // 동일한 참조를 갖는 같은 인스턴스이다. true

쓰기 지연

쿼리를 모아놨다가 한번에 보낸다. 데이터베이스와의 네트워크 비용이 줄어든다.

엔티티매니저.저장해주세요(엔티티); // 영속성 컨텍스트에 객체가 담긴다.

엔티티 저장을 요청하면 영속성 컨텍스트에 객체가 담긴다. 그러나 이때 DB에 즉시 저장되는 것은 아니다.
저장을 요청받은 시점에 쿼리를 만들어 쿼리지연 보관소에 담아놓았다가 트랜잭션이 종료되기 직전에 DB로 쿼리를 몽땅 내보낸다.

물론 이 외에도 모아져있던 쿼리가 나가는 시점이 존재한다. JPQL, flush()호출, 트랜잭션 종료 직전.

flush

쿼리 지연 보관소에 쌓인 쿼리를 DB로 내보낸다. 영속성 컨텍스트와 DB가 동기화가 된다.

flush 직접호출, JPQL실행시, 트랜잭션이 종료되기 직전에 해당 작업이 호출되도록 기본 설정되어있다.

변경 감지

Dirty Checking. 영속성 컨텍스트에 담긴 객체가 수정된 사항이 없는지 확인하는 작업

jpa는 객체의 수정메서드를 제공하지 않는다. 단지 영속성 컨텍스트에 객체가 담긴 시점에 스냅샷(저장시점 상태)을 찍어 원본 객체와 함께 보관한다.

쿼리저장소에 모인 쿼리가 db로 출발하려는 시점(flush)에 스냅샷과 현재 객체의 상태를 비교해 변경된 부분을 확인한다.

변경 사항이 존재하면 쿼리지연 저장소에 수정(update) 쿼리가 등록된다. 해당 쿼리가 함께 DB로 출발한다.

객체의 삭제요청

엔티티매니저는 객체의 삭제요청을 받을 수 있다. 삭제요청을 받은 객체는 즉시 영속성컨텍스트에서 제거되며, DB로의 반영은 flush 시점까지 지연된다.

엔티티매니저.삭제(대상엔티티); 
// 즉시 영속성컨텍스트에서 제거. db반영은 쿼리지연 저장소가 flush 될때가지 미루어진다.

지연로딩

포함관계에 있는 객체를 조회할때 까지 쿼리가 지연된다.

객체안에 특정 객체가 포함되어있을때 jpa는 이를 깡통객체로 초기화한다.

@Entity
class 학생 {
    String name;
    String age;
    신분증 idCard;

}

class 신분증 {
    String id;
    int width;
    int height;
}

위와같이 학생이 신분증을 포함하는 관계일때 jpa는 자바 어플리케이션에서 신분증의 정보를 요구하기 까지 DB에 신분증에 대한 select 쿼리를 날리지 않는다.

대신 신분증을 상속받은 프록시 객체를 깡통으로 만들어 학생 객체에 넣어놓는다. 실제로 해당 깡통에 대해 신분증정보를 요구하는 메서드가 호출되면 DB에 select쿼리를 보내게 된다.

0개의 댓글