🔙뒤로가기

영속성 컨텍스트의 엔티티 관리방법 “캐시”

영속성 컨텍스트는 엔티티를 관리하기 위해 캐시를 사용한다. 캐시는 일종의 메모리 저장소로, 엔티티의 상태를 임시로 저장하고 관리한다. JPA 구현체(예: Hibernate)는 영속성 컨텍스트를 통해 엔티티의 생명주기를 관리하며, 엔티티의 변경 사항을 데이터베이스에 동기화한다.

영속성 컨텍스트의 캐시 기능은 다음과 같은 이점을 제공한다.

  1. 1차 캐시 : 영속성 컨텍스트는 1차 캐시를 사용하여 엔티티를 관리한다. 1차 캐시는 트랜잭션 범위의 캐시로, 같은 트랜잭션 내에서 엔티티를 조회하면 이미 캐시에 있는 엔티티를 반환한다. 이를 통해 동일한 엔티티에 대한 중복 조회를 줄이고 성능을 향상시킬 수 있다.
  2. 변경 감지(Dirty Checking) : 영속성 컨텍스트는 엔티티의 상태 변화를 추적한다. 트랜잭션 커밋 시, 변경된 엔티티의 상태를 데이터베이스에 동기화하므로 개발자는 변경 사항을 수동으로 저장할 필요가 없다.
  3. 지연 로딩(Lazy Loading) : 캐시를 사용하면 연관된 엔티티를 필요할 때까지 로딩을 지연시킬 수 있다. 이를 통해 성능 최적화를 할 수 있으며, 불필요한 데이터 조회를 줄일 수 있다.
  4. 엔티티 동일성(identity) 보장 : 영속성 컨텍스트는 같은 트랜잭션 범위에서 동일한 식별자를 가진 엔티티에 대해 동일성을 보장한다. 이를 통해 엔티티의 일관성을 유지할 수 있다.

[package hellojpa;

import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence;

public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try{
        Member member = new Member();
        member.setId(4l);
        member.setName("test");
        em.persist(member);

// Member findMember = em.find(Member.class, 4l); // System.out.println("findMember.getId() = " + findMember.getId()); // System.out.println("findMember.getName() = " + findMember.getName()); System.out.println("findMember.getId() = " + member.getId()); System.out.println("findMember.getName() = " + member.getName());

        member.setName("testUpdate");

// em.merge(member); // Member updatedMember = em.find(Member.class, 4l); // System.out.println("updatedMember.getId() = " + updatedMember.getId()); // System.out.println("updatedMember.getName() = " + updatedMember.getName());

        System.out.println("updatedMember.getId() = " + member.getId());
        System.out.println("updatedMember.getName() = " + member.getName());

        em.remove(member);

        tx.commit();
    } catch (Exception e) {
        tx.rollback();
    } finally {
        em.close();
    }

    emf.close();
}

}](https://willneiman.notion.site/package-hellojpa-import-javax-persistence-EntityManager-import-javax-persistence-EntityManagerFac-91b7e804c0a34d4a80aecf88f1b64cc3) 의 crud 코드 각 단계에 주석을 달아 설명하면 다음과 같다.

// 영속화 전, 그저 자바 객체인 상태
Member member = new Member();
member.setId(4l);
member.setName("test");

// 새로운 객체를 데이터베이스에 저장하려고 하며, 이때부터 EntityManager가 관리하기 시작한다.
// 영속성 컨텍스트에 객체를 넣어 관리하도록 함. (실제 데이터베이스에 저장은 커밋 시점에 발생)
em.persist(member);

// 영속화된 객체의 정보를 출력
System.out.println("member.getId() = " + member.getId());
System.out.println("member.getName() = " + member.getName());

// 영속화된 객체의 속성을 변경. 영속성 컨텍스트 내에서 변경 감지(dirty checking)가 발생.
member.setName("testUpdate");

// 변경된 객체의 정보를 출력. 다만 여기서는 그저 자바 객체의 변경일 뿐이다.
System.out.println("member.getId() = " + member.getId());
System.out.println("member.getName() = " + member.getName());

// 영속성 컨텍스트에서 객체를 삭제하도록 함. 실제 데이터베이스에서 삭제는 커밋 시점에 발생
// em.remove를 호출한 시점에서 영속성 컨텍스트는 이 객체를 관리하지 않는다. (준영속 상태)
em.remove(member);
// 만약 여기서 remove()를 사용하지 않는다면 dirty checking에 의해 UPDATE문이 호출됨.

// 트랜잭션 커밋 시점. 영속성 컨텍스트가 실제 데이터베이스에 변경 사항을 반영한다.
// 객체가 영속성 컨텍스트에서 제거되었기에 실제 데이터베이스에 아무런 변화가 없다.
// 영속성 컨텍스트 내부에서 발생한 insert와 delete는 데이터베이스와 동기화될 때 적용되며, 
// 이 경우 실제로 데이터베이스에는 아무런 변화가 없어진다.
tx.commit();