Hyeok의 웹 개발 블로그

<2025.05.01> 영속성 컨텍스트 본문

TIL/Spring

<2025.05.01> 영속성 컨텍스트

Yhyeok 2025. 5. 1. 20:21

✅영속성이란?

  • 영속성( 永(길게) 續(속하다) - Persistence)이란, 프로그램이 종료된 이후에도 데이터가 사라지지 않고 저장되는 성질을 말합니다.
  • 즉, 메모리(휘발성 공간)가 아닌 디스크(비휘발성 저장소)에 데이터를 영구히 보존하겠다라는 강력한 의지가 나타내기 위한 것입니다.

 

✅JPA에서 영속성이란?

  • JPA는 객체(Entity)와 데이터베이스 테이블(Table)간의 중간자 역할을 하며, 자바 객체를 데이터베이스에 ‘영속’시키는 과정을 관리하기 위한 라이브러리에요.
  • 한명의 유치원 선생님이 여러 유치원생을 관리하려면 유치원이라는 환경이 필요하듯 여러 객체를 관리하기 위한 환경이 바로 영속성 컨텍스트(Persistence Context) 라는 메모리 영역을 필요해요.
  • 그래서 JPA에서의 영속성은 영속성 컨텍스트(Persistence Context) 에 등록한 객체의 추이를 관찰하다 DB에 어떻게 영구히 저장할 것인가를 정하는 과정인 것이죠.
  • JPA에서 영속은 영속성 컨텍스트에 객체를 등록된 상태.
    - 영속 (managed)
     - 영속성 컨텍스트에 등록된 상태
     - find(),save()  

    - 비영속(new/transient)
     - 영속성 컨텍스트에 등록되지 않은 상태

    - 준영속 (detached)
     - 영속성 컨텍스트에 저장되었다가 분리된 상태
     - 준영속 상태의 엔티티는 컨텍스트가 제공하는 기능을 사용X
     - clear() , refresh() 

    - 삭제(removed)
     - 영속성 컨텍스트에서 제외되며 SQL 저장소에 delete문을 저장
     - delete()

    - 반영(flush)
     - 현재 영속성 컨텍스트에 상태를 확인하여 SQL 생성 후 데이터베이스에 query를 전송
     - 단, commit 전이기 때문에 데이터베이스에 실제로 저장되지 않은 상태
     - flush()

 


✅영속성 컨텍스트에서 객체 관리
 

  • EntityManager가 객체를 관리하고 배출하는 곳은 EntityManagerFactory 에서 나오고, 배출 되는 시점은 transaction이
    시작 될 때이다. 
  • 생성된 EntityManager는 스프링은 내부적으로 발행된 TransactionThread에 바인딩되기 때문에 해당 트랜잭션 동안
     동일한 EntityManager 인스턴스를 재사용할 수 있게 된다.


✅영속성 컨텍스트의 특징

  • 1차 캐시 & 동등성 보장
    - 영속성 컨텍스트 내부에는 캐시라는 이름의 Map<@Id, Entity> 형태의 자료 구조가 존재
    - 캐시는 동일 트랜잭션 내에서만 유효한 로컬 캐시
    - 같은 엔티티를 반복 조회할 때, DB 접근 횟수를 줄여줌
    - 실무 고려사항 : 대량의 데이터를 처리하는 배치 작업에서는 주기적으로 영속성 컨텍스트를 초기화 clear() 하여 메모리 사용량 관리 필요가 있어요. 다만 clear() 했다고해서 대량의 데이터가 stack memory에서 없어지는건 아니기 때문에 OutOfMemory를 조심해야해요.

 

  • 쓰기 지연
    - JPA는 SQL을 즉시 실행하지 않고 영속성 컨텍스트 내의 쓰기 지연 SQL 저장소에 모아둔다.
    - transaction.commit() 시점에 모아둔 SQL을 한 번에 DB로 전송
    - 작동 과정
      1. em. persist(entity)호출 : 엔티티를 1차 캐시에 저장 + INSERT SQL 생성 후 쓰기 지연 SQL 저장소에 보관
      2. transaction.commti() 호출 : flush() 자동 호출 > 쓰기 지연 SQL 저장소의 쿼리들을 DB에 전공 > 실제 커밋
    - commit 전 flush()를 통해 DB에 반영되는 경우
      - repository.flush() 직접 호출 시
      - JPQL 쿼리 실행 전 (자동)
      - 식별자 생성 전략이 GenerationType.IDENTITY인 경우 save() 호출 시 즉시 INSERT SQL 실행
  • 변경 감지 (Dirty Checking)
    - 트랜잭션 내에서 엔티티 값이 변경되면, 커밋 시점에 자동으로 UPDATE SQL이 생성
    - 별도의 update() 메소드 호출이 필요 없는 것이 JPA의 큰 특징
    - 변경 감지의 동장 원리
      1. 트랜잭션 시작 시, 엔티티의 최초 상태 스냅샷을 저장
      2. 플러시 시점에 현재 엔티티와 스냅샷을 비교 하여 변경된 엔티티 탐지
      3. 변경된 엔티티가 있으면 UPDATE SQL 생성 후 DB에 전송

    - 변경 감지 최적화 관점
    • JPA는 기본적으로 엔티티의 모든 필드를 업데이트하는 SQL을 생성해요.
    • 필드가 많은 엔티티의 경우 변경 필드만 업데이트하도록 설정 가능하죠.