3장 영속성 관리

2장 JPA 시작은 초기 설정 관련 내용 이기에 스킵한다.

EntityManagerFactory

  • EntityManager 를 관리하는 곳

  • Persistence 객체가 설정 정보를 조회, 바탕으로 만들어진다.

  • 설정 정보에 명시된 DB를 연결, 클라이언트 요청이 들어오면 커넥션 풀에 커넥션을 확인 후 EntityManager 생성, 커넥션과 연결해준다.

  • 여러 스레드에서 접근, 공유 가능하다.

  • 보통 DB 하나 당 하나만 생성, 공유

EntityManager

  • 말 그대로 Entity (객체)를 관리하고 기능을 수행하는 역할이다.

  • 객체를 관리하는 작은 DB라고 이해했다.

  • EntityManagerFactory 에서 생성되며 각 트랜잭션 (요청 쓰레드) 하나당 하나 씩만 사용된다.

  • EntityManagerFactory 와 는 다르게 공유, 재사용이 불가 (커넥션 관련 동시성 문제 때문)

  • 실제 DB와 커넥션을 가지고 트랜잭션을 수행한다. 고로 공유될수없다.

EntityTransaction

  • 조회를 제외한 거의모든 DB의 접근하는 로직은 EntityTransaction 안에서 수행되어야 한다.

  • 만약 이렇게 처리 되지 않은 명령들은 TransactionRequiredException을 일으킨다.

  • EntitiyManager 가 얻을수있으며 트랜잭션 begin ~ commit 사이에서 DB 접근이 가능하다.

Persistence Context (영속성 컨텍스트)

  • Entity 를 영구히 저장하는 환경이라 칭하지만 필자는 EntityManager를 통해 em.persist(Entity) ~ em.detached 하기 전 까지는 영구히 저장하는 환경이라 이해했다.

  • 애플리케이션 ~ DB 사이에서 객체를 보관하는 가상의 DB 역할

  • EntityManager 통해 객체를 저장하거나 조회하면 영속성 컨텍스트에 저장함

Entity 의 생명주기

  1. 비영속

  • 영속성 컨텍스트에 영속되지 않은 상태를 의미

  1. 영속

  • em.persist(), em.find(), JPQL로 조회한 엔티티 등이 영속 상태에 속한다.

  • JPQL 로 조회하면 영속 상태에 속하게됨

** JPQL 은 조회 시 먼저 DB 에 접근하여 데이터를 가져오고 해당 데이터가 영속성 컨텍스트에 존재한다면 가져온 데이터를 날리고 영속성 컨텍스트에 있는 데이터를 사용한다.

  1. 준영속

  • em.detach : 특정 엔티티를 준영속 상태로 전환한다.

  • em.close (영속성 컨텍스트 종료), em.clear(영속성 컨텍스트 초기화) 를 할 경우 해당 영속성 컨텍스트에 있던 엔티티는 준영속 상태가 된다.

  • 영속 상태에 있다가 영속상태가 종료된 상태를 의미

  • 비영속에 가까우며 영속성 컨텍스트가 제공하는 기능 사용 X

  • 식별자값 보유 (이미 한번 영속 됬었기 때문)

  1. 삭제

  • em.remove(entity) : 엔티티를 DB, 영속성 컨텍스트 에서 삭제한다.

영속성 컨텍스트의 특징

  • 영속성 컨텍스트는 식별자 값을 가지고 있다. 흔히 @Id를 통해 테이블과 매핑한 값이다.

  • Map 형태로 되어있고 식별자값 : Entity(인스턴스) 같은 형식으로 이루어져있다.

장점

  1. 1차 캐시 사용

em.find(entity) 를 호출하면 1차 캐시 (영속성 컨텍스트) 를 조회해서 객체가 없다면 DB를 조회해 객체를 가져온뒤 1차 캐시에 보관한다. 만약 1차 캐시 안에 있다면 그 엔티티를 가져온다.

후에 조회 시에는 1차 캐시를 통해서만 조회하기에 이점을 드러낸다.

반면에 위에 써놨듯이 JPQL은 호출 시 1차캐시가 아닌 DB를 우선으로 조회한다. SQL 문으로 바꿔서 호출하기 때문이다.

  1. 동일성 보장

Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");

System.out.println(a == b) // 동일성 보장

두 조회문 모두 1차 캐시, 즉 영속성 컨텍스트에서 가져오기에 동일성이 보장된다.

  1. 변경 감지 (Dirty Check)

영속성 컨텍스트에서 엔티티를 조회 한 뒤 객체.SET() 을 이용해 수정하는 로직이 있다.

이때 조회한 엔티티를 업데이트하는 코드가 없어도 트랜잭션을 커밋한다면 Entity Manager 내부에서 플러시를 호출한다.

영속성 컨텍스트가 기존 *스냅샷 과 수정된 1차 캐시를 비교하여 자동으로 UPDATE에 해당하는 SQL을 생성해준다. (영속 상태의 엔티티에만 적용)

(그래서 인지 JPA에는 따로 업데이트 쿼리메소드가 없다. 필자도 업데이트 관련 로직은 따로 set 메서드를 만들어 사용했다.)

** 스냅샷이란 영속성 컨텍스트가 엔티티를 저장할때, 컬렉션으로 또 다른 복사본을 저장하게 되는것을 의미한다.

(주의) JPA 의 기본전략은 엔티티의 모든 필드를 업데이트 한다는것이다. 내가 수정한 컬럼 뿐 아니라 모든 컬럼을 업데이트 하는것 고로 DB에 보내지는 데이터 양이 증가한다. 하지만 수정 쿼리가 항상 같아서 미리 생성해두거나 이전에 한번 파싱한 쿼리는 재사용이 가능하다.

  1. 지연로딩 ( Lazy Loading)

  • 연관 관계가 있는 엔티티 조회 시 일단 연관 관계에 있는 엔티티는 프록시 객체로 반환하고, 실제로 사용할때 쿼리를 날려 가져오는 기능이다.

플러시 (Flush)

  • 영속성 컨텍스트에 있는 변경내용을 DB에 반영한다.

변경감지가 동작하고 수정 상황을 스냅샷과 비교하여 업데이트 쿼리를 생성 한 뒤 지연로딩 SQL 저장소에 보내고 해당 지연로딩 SQL 저장소가 쿼리를 DB로 보내는 일련의 작업을 시작하는 명령어이다.

플러시를 사용하는 방법

  1. em.flush() 호출

  2. 트랜잭션 커밋 시

  3. JPQL 쿼리 실행

Merge()

준영속 상태의 엔티티를 가져와서 해당값을 영속 상태의 엔티티에 넣은 뒤 반환한다.

준영속 상태의 엔티티의 식별자값을 가지고 1차캐시 ~ DB를 조회 한 뒤 준영속 상태의 엔티티의 값을 조회한 영속 상태의 엔티티에 담아서 반환 한다. Save or Update 기능이라고 할수있다.

정리

EntityFactoryManager 에서 EntityManager가 만들어지며 EntityManager는 영속성 컨텍스트를 가진다.

EntityFactoryManager 는 DB 당 하나이며 공유가 가능하지만 EntityManager 는 요청 당 하나이며 공유가 불가능하다.

영속성 컨텍스트에는 다양한 기능을 제공해주며 엔티티의 생명주기 상태에 따라 해당 기능의 적용 여부가 달라진다.

Last updated