JPA 영속성 컨텍스트란?

나길진·2023년 12월 20일
0

본 내용은 인프런의 김영한 님의 강의내용이 포함되어 있습니다.
자바 ORM 표준 JPA 프로그래밍 - 기본편


영속성 컨텍스트란 엔티티를 영구히 저장하는 환경이라고 할 수 있다. 이게 무슨말이냐면 데이터를 영구히 저장할 수 있는 DB와 애플리케이션 사이에서 여러가지 편의성과 이점을 제공해주는 환경이라고 할 수 있다.

영속성 컨텍스트는 엔티티 매니저를 통해 접근 할 수 있는데 애플리케이션에서 생성한 엔티티를 DB에 추가해주거나 변경 및 조회를 영속성 컨텍스트에서 관리하고 있다.

엔티티 생명주기

영속성 컨텍스트에서 엔티티를 관리할 때 생명주기가 있는데 4단계로 분류하고있다.

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

예시

비영속

엔티티를 생성만하고 영속성 컨텍스트에 저장하지 않은 상태이다. 즉 JPA와 전혀 관련없는 상태이다.

// 객체를 생성만하고 영속성 컨텍스트에 저장하지 않은 상태
Member member = new Member();

영속

생성한 엔티티를 영속성 컨텍스트에 저장한 상태

EntityManager em = EntityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();

tx.begin();
Member member = new Member();
// 엔티티 매니저를 통해 영속성 컨텍스트에 엔티티를 저장시킨다.
em.persist(member);

준영속

영속성 컨텍스트에서 관리하던 엔티티를 컨텍스트에서 제거한 상태

EntityManager em = EntityManagerFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();

tx.begin();
Member member = new Member();
// 엔티티 매니저를 통해 영속성 컨텍스트에 엔티티를 저장시킨다.
em.persist(member);
// 엔티티를 영속성 컨텍스트에서 제거시킨다.
em.detach(member);

detach말고도 clear(), close()를 통해서 엔티티 개별적으로 제거하는게 아닌 영속성 컨텍스트를 전체 초기화 하거나 닫아서 일괄적으로 준영속 상태로 만들 수 있다.

삭제

삭제는 글로만 보면 준영속 상태랑 헷갈릴 수 있는데 실제로 DB에서 삭제하는 것을 삭제라고 한다.

em.remove(member);

장점

영속성 컨텍스트의 장점은 5가지 정도 있다.
1. 1차 캐시
2. 동일성
3. 트랙잭션을 지원하는 쓰기 지연
4. 변경 감지
5. 지연 로딩

1차 캐시

1차 캐시는 영속성 컨텍스트 내부에 캐시가 존재하는데 이를 1차 캐시라고 부른다. Map형태로 key값은 엔티티의 pk값으로 저장시킨다. value는 엔티티 자체를 저장시키고 DB에서 한번 불러온데이터는 1차 캐시에 먼저 저장 시킨후 불러온다. 이렇게 함으로써 같은 데이터를 불러올 때 DB에 접근하는 횟수를 줄일 수 있다.

동일성

우리는 객체지향적 코딩을 하려고 jpa를 사용한다. 자바 컬렉션에서 데이터를 꺼내올 때마다 다른 인스턴스를 가져오는가? 그렇지않다. 그렇기때문에 pk값이 같은 엔티티라면 jpa를 통해서 가져올 때에도 같은 엔티티를 가져와야한다고 생각한다. 같은 엔티티를 가져올 수 있는것은 1차 캐시에서 가져오기 때문이다.

Member member1 = em.find(Member.class, 1L);
Member member2 = em.find(Member.class, 1L);

System.out.println(member1 == member2) // true

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

jpa는 영속성 컨텍스트에 저장시킨다고 바로 DB에 저장시키지 않는다. 이유는 로직 도중에 오류가 발생한다면 다시 되돌리는 작업이 힘들기 때문에 모든 로직이 다 완료되었을 때 commit 요청을 통해서 일괄적으로 DB에 저장시키기 위함이다.
이런 동작을 하기 위해서 영속성 컨텍스트내에서 새로운 엔티티가 추가되거나 변경될 때 1차 캐시에 추가하고 내부에 있는 쓰기지연 SQL 저장소에 SQL문으로 저장시켜놓고 일괄적으로 작업을한다.일종의 버퍼 역할을 하고있다고 보면 된다.

변경 감지

jpa에서 엔티티를 수정할 땐 엔티티의 값을 수정하는 작업이외에 별다른 작업을 하지 않는다. 그렇게 작동할 수 있는 이유는 1차 캐시에 엔티티의 원본데이터를 저장하는 스냅샷을 가지고 있기 때문이다. flush가 작동할 때 스냅샷과 엔티티의 값을 비교해서 변경된 부분이 있으면 쓰기지연 SQL 저장소에 UPDATE SQL 쿼리가 저장되어 commit할 때 일괄적으로 변경한다.

지연 로딩

지연로딩은 다른 테이블과 JOIN으로 같이 불러왔을 때 사용되는 개념인데 간단하게 이야기하면 해당 엔티티를 사용할 때 SQL을 불러온다 라고 생각하면 될 듯하다.

profile
백엔드 개발자

0개의 댓글

관련 채용 정보