enginner_s2eojeong

[자바 ORM 표준 JPA 프로그래밍] 03.영속성 관리 본문

Backend/Database

[자바 ORM 표준 JPA 프로그래밍] 03.영속성 관리

_danchu 2025. 3. 19. 22:51


1. 영속성 컨텍스트 (Persistence Context)

  • 정의: JPA에서 영속성 컨텍스트는 엔티티 객체가 영구적으로 저장되는 환경을 말한다.
  • EntityManger.persist(entity)로 엔티티를 영속성 컨텍스트에 저장할 수 있다.
  • EntityManager를 통해 영속성 컨텍스트에 접근하고 이를 관리한다.
  • 엔티티의 생명주기를 관리하고 트랜잭션 내에서 엔티티의 상태를 자동으로 추적해준다.

2. 엔티티 생명주기

  • 비영속 (Transient): 엔티티 객체가 새로 생성되었지만 영속성 컨텍스트에 의해 관리되지 않는 상태
  • 영속 (Managed): 엔티티 객체가 영속성 컨텍스트에 의해 관리되는 상태
  • 준영속 (Detached): 영속성 컨텍스트에서 분리된 엔티티로 더 이상 관리되지 않는 상태
  • 삭제 (Removed): 엔티티가 삭제된 상태

3. 영속성 컨텍스트의 이점

  • 1차 캐시: JPA는 1차 캐시를 제공하여 데이터베이스에서 엔티티를 조회할 때마다 데이터베이스에 매번 쿼리를 보내지 않고 캐시된 데이터를 사용한다.

em.persist()에서 1차 캐시에 저장이 되기 때문에 em.find()에서 SELECT 쿼리가 나가지않은 것을 확인할 수 있다.

  • 동일성 보장: 동일한 엔티티는 영속성 컨텍스트 내에서 같은 객체로 취급된다.

findMember1과 findMember2는 같은 엔티티이기 때문에 1번만 SELECT 쿼리로 조회하고, 이후에는 1차 캐시에 저장된 것을 알 수 있다.

  • 트랜잭션 지원: 데이터베이스에 대한 쓰기 지연을 트랜잭션 단위로 관리하고 한 번의 커밋으로 여러 변경을 처리할 수 있다.
    • 트랜잭션 커밋 시에 쓰기 지연 SQL 저장소에 쌓아놓은 쿼리들을 데이터베이스에 보낸다.

"--------" 를 기준으로 확인해보면, tx.comit()을 해서 INSERT 쿼리문이 생성된 것을 알 수 있다.

 

+)

persistence.xml

<property name="hibernate.jdbc.batch_size"  value="10"/>

 

batch size를 지정해서 데이터베이스로 쿼리를 한꺼번에 보낼 수 있다.

  • 변경 감지 (Dirty Checking): 엔티티의 상태가 변경되면 자동으로 이를 감지하여 데이터베이스에 반영한다.
    • JPA 트랜잭션이 커밋되는 시점에 내부적으로 flush()도 호출이 되면서 스냅샷과 기존 엔티티를 비교한 후, 바뀐 부분이 있다면 UPDATE 쿼리를 쓰기 지연 SQL 저장소에 쌓는다.

  • 지연 로딩 (Lazy Loading): 엔티티와 연관된 다른 객체는 필요할 때까지 로드되지 않아 성능이 최적화 된다.

4. 엔티티 조회 및 플러시(Flush)

  • 플러시:
    • 영속성 컨텍스트에서 변경된 내용을 데이터베이스에 반영하는 과정.
    • 쓰기 지연 SQL 저장소에 쌓아뒀던 쿼리들이 데이터베이스로 날라간다.
    • flush() 메서드를 통해 명시적으로 호출하거나 트랜잭션 커밋 시 자동으로 발생한다.
    • JPQL 쿼리 실행시에도 플러시가 자동으로 호출된다.

  • 플러시 모드: 
    • FlushModeType.AUTO는 기본값으로, 커밋이나 쿼리 실행 시 플러시가 자동으로 발생한다. 
    • FlushModeType.COMMIT커밋 시에만 플러시가 일어난다.

5. 준영속 상태로 전환

  • 엔티티를 준영속 상태로 전환하려면 
    • detach() 메서드를 사용하여 엔티티를 분리하거나, 
    • clear() 메서드로 영속성 컨텍스트 자체를 통채로 초기화하거나,
    • close() 메서드로 영속성 컨텍스를 종료하면 된다.
  • 그러면 이후에는 영속성 컨텍스트가 제공하는 기능을 사용하지 못하게 된다. (ex. dirty checking)

detach()

SELECT 쿼리만 나가고 UPDATE 쿼리는 나가지 않은 것을 확인할 수 있다.

 

close()

em.close()로 영속성 컨텍스트를 초기화 한 후, 같은 엔티티를 조회하면 다시 영속성 컨텍스트에 의해 관리되는 상태가 되므로 SELECT 쿼리가 각각 호출된 것을 확인할 수 있다.