[Spring] 영속성 컨텍스트

Neo-Renaissance·2024년 12월 26일

영속성 컨텍스트(Persistence Context)란?

영속성 컨텍스트(Persistence Context)는 JPA(Java Persistence API)에서 엔티티(Entity) 객체를 관리하는 캐시 같은 메모리 공간입니다. 영속성 컨텍스트는 데이터베이스와 애플리케이션 간의 중간 계층 역할을 하며, 엔티티 객체를 관리하고 데이터베이스와 동기화합니다.

영속성 컨텍스트의 주요 개념

1. 엔티티 상태(Entity States)

엔티티는 영속성 컨텍스트에서 다음과 같은 상태를 가질 수 있습니다:

  • 비영속(New/Transient)
    - 영속성 컨텍스트가 관리하지 않는 상태. 단순히 메모리에 객체가 생성된 상태.
    - 예: new Member()를 호출했지만 저장하지 않은 상태.
Member member = new Member(); // 비영속 상태
  • 영속(Managed)
    - 영속성 컨텍스트가 관리하는 상태로, 데이터베이스와 동기화될 준비가 된 상태.
    - EntityManager.persist()를 호출하거나, find() 메서드로 조회한 엔티티는 영속 상태가 됩니다.
em.persist(member); // 영속 상태로 전환
  • 준영속(Detached)
    - 영속성 컨텍스트에서 분리된 상태로, 더 이상 관리되지 않는 상태.
    - EntityManager.detach() 또는 clear()를 호출하거나 트랜잭션이 종료되면 발생.
em.detach(member); // 준영속 상태
  • 삭제(Removed)
    - 영속성 컨텍스트에서 삭제된 상태로, 트랜잭션 커밋 시 데이터베이스에서도 삭제됩니다.
em.remove(member); // 삭제 상태

2. 1차 캐시(First-Level Cache)

영속성 컨텍스트는 1차 캐시를 이용하여 동일한 엔티티를 한 번만 데이터베이스에서 조회합니다.
동일한 트랜잭션 내에서 find()로 같은 ID의 엔티티를 두 번 조회하면, 두 번째는 데이터베이스를 조회하지 않고 1차 캐시에서 반환합니다.

Member member1 = em.find(Member.class, 1L); // DB에서 조회 후 1차 캐시에 저장
Member member2 = em.find(Member.class, 1L); // 1차 캐시에서 반환
System.out.println(member1 == member2);    // true (동일 객체)

3. 변경 감지(Dirty Checking)

영속성 컨텍스트는 엔티티의 변경 사항을 추적하여, 트랜잭션 커밋 시 자동으로 변경 내용을 데이터베이스에 반영합니다. persist()를 호출하지 않아도, set 메서드를 통해 값이 변경되면 자동으로 업데이트 쿼리를 생성합니다.

Member member = em.find(Member.class, 1L);
member.setUserName("updatedName"); // 변경 감지
// 트랜잭션 커밋 시 UPDATE 쿼리 실행

4. 쓰기 지연(Write-Behind)

영속성 컨텍스트는 트랜잭션 커밋 전까지 SQL 쿼리를 데이터베이스에 전송하지 않고 모아둡니다.
트랜잭션이 종료되면 한 번에 데이터베이스로 쿼리를 전송하여 성능을 최적화합니다.

em.persist(member1); // INSERT 쿼리 생성 (DB로 전송 X)
em.persist(member2); // INSERT 쿼리 생성 (DB로 전송 X)
em.flush();          // 쿼리 전송

5. 지연 로딩(Lazy Loading)

영속성 컨텍스트는 필요할 때만 데이터를 로딩하는 지연 로딩(Lazy Loading)을 지원합니다. @OneToMany, @ManyToOne 등 연관된 엔티티를 사용할 때, 실제로 데이터가 필요할 때만 쿼리를 실행합니다. LazyInitializationException은 영속성 컨텍스트가 닫힌 상태에서 지연 로딩을 시도할 때 발생합니다.

영속성 컨텍스트의 장점

  1. 성능 최적화
    1차 캐시를 통해 중복 쿼리를 방지하여 데이터베이스 접근을 줄임.
    쓰기 지연을 통해 다수의 쿼리를 한 번에 처리하여 성능을 개선.

  2. 변경 감지와 자동 동기화
    엔티티의 변경 사항을 자동으로 감지하고, 데이터베이스에 반영.
    개발자가 직접 SQL을 작성하지 않아도 되는 장점.

  3. 트랜잭션 관리
    동일한 트랜잭션 내에서 데이터 일관성을 보장.

영속성 컨텍스트의 동작 흐름

트랜잭션 시작 → 영속성 컨텍스트 생성.
엔티티 저장 → 영속성 컨텍스트가 엔티티를 관리.
엔티티 변경 → 변경 감지로 변경 사항 추적.
트랜잭션 커밋 → 쓰기 지연된 쿼리 실행 및 동기화.
트랜잭션 종료 → 영속성 컨텍스트 종료 및 1차 캐시 초기화.

profile
if (실패) { 다시 도전; } else { 성공; }

0개의 댓글