본문 바로가기
Java | spring/JPA

JPA 영속성 컨텍스트 및 내부 동작 방식

by 워니 wony 2023. 10. 8.

JPA를 처음 학습하는 경우에 영속성 컨텍스트가 무슨 의미인지 이해하기가 쉽지 않다.

사실 사용하다 보면 자연스럽게 이해가 되긴 하는데, 처음에 해당 개념을 제대로 이해하지 않으면 내 생각과 다르게 동작하는 것을 보면서 아주 당황할 수 밖에 없다. 그래서 제대로 이해하고 넘어가는 것이 좋다.

 

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

  • JPA 이해 시 가장 중요한 용어
  • entity 영구 저장하는 환경
  • 영속성 컨텍스는 논리적인 개념
  • entityManager를 통해 영속성 컨텍스트에 접근
    • entity를 저장하거나 조회하면 entityManager는 영속성 컨텍스트에 엔티티를 보관하고 관리함

 

위에 내용만으로 바로 이해가 되지 않는 것이 정상이다!

 

보통 애플리케이션에서 데이터베이스에 데이터를 저장하거나 조회하려면 SQL을 날려서, 데이터를 저장하거나 조회한 데이터를 받게 된다. JDBC 같은 기술을 사용해서 SQL을 날리고, 데이터를 받아서 JAVA 애플리케이션에서 사용하게 된다.  

 

JPA는 애플리케이션과 JDBC 사이에서 동작하는 가상 데이터베이스라고 생각하면 된다. 데이터를 저장하는 경우 일반적인 경우 SQL insert 문을 바로 날려서 처리를 하지만, JPA를 사용하게 되면 DB에 바로 저장하는게 아니라 영속성 컨텍스트에 먼저 영속 상태로 만든다. 엔티티 매니저를 통해서 영속성 컨텍스트에 먼저 보관하고 관리하는 것이다. 그리고 트랜잭션이 커밋되는 시점에 DB에 반영하게 된다.   

영속성 컨텍스트가 있음으로 인해서 1차 캐시를 하거나, 동일성을 보장하거나 변경을 감지해서 데이터를 변경하는 등의 작업을 할 수 있게 된다. 1차 캐시가 되면, 동일한 데이터를 조회 하는 경우 DB에 쿼리를 계속 날리는 것이 아니라 캐시에 데이터가 있으면 그걸 조회해서 리턴해 준기 때문에 약간의 조회 성능이점이 있을 수 있다. 또한 영속성 컨텍스트는 엔티티를 엔티티 매니저를 통해 persist 하는 경우에 바로 쿼리를 실행하는 것이 아니라 트랜잭션을 커밋할 때 까지 insert 쿼리를 모아서 커밋 시점에 쿼리가 실행 되기 때문에 최적화를 할 수 있는 여지가 있다. (버퍼링 기능) 

 

영속성 컨텍스트 이점

  • 1차 캐시
  • 동일성 보장
  • 변경 감지(Dirty Checking)
  • 지연 로딩(Lazy Loading)
  • 트랜잭션을 지원하는 쓰기 지연

 

 

 

영속성 컨텍스트 내에서 관리되는 엔티티의 생명 주기는 아래와 같이 구분할 수 있다.

엔티티 매니저를 통해서 엔티티의 상태를 변경 할 수 있다. 참고로 엔티티가 영속성 상태가 되었다고 아직 DB에 해당 데이터 쿼리가 날아간 것은 아니다. 커밋을 하거나 엔티티 매니저를 통해 flush해야 DB에 반영이 된다.

 

 

엔티티 생명 주기 (Entity Life Cycle)

  • 비영속(new) : 영속성 컨텍스트와 관계 없는 새로운 상태
  • 영속(managed) : 영속성 컨텍스트에서 관리되는 상태
  • 준영속(detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제(removed) : 삭제된 상태

 

 

New : 비영속 상태

객체를 생성만 한 상태를 말한다. 아래와 같이 엔티티를 생성만 한 상태를 비영속 상태의 엔티티라고 한다.

TeamEntity teamEntity = new TeamEntity();
teamEntity.setName("Team1");

 

 

Managed : 영속 상태

엔티티 매니저로 persist 한 상태로, 영속성 컨텍스트에서 관리되는 상태이다. 영속성 컨텍스트에서 관리하고 있기 때문에 동일 id를 가진 엔티티를 조회하는 경우 DB가 아닌 1차 캐시된 곳에서 조회 후 데이터를 리턴하게 된다.

(참고로 아래 코드는 em.flush()를 하거나 트랜잭션을 커밋하지 않았기 때문에 DB에 반영되지는 않은 상태이다.)

TeamEntity teamEntity = new TeamEntity();
teamEntity.setName("Team1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

em.persist(teamEntity);

 

Detached : 준영속 상태

영속성 컨텍스트에 저장되었다가 분리된 상태가 준영속 상태이다. 준영속 상태를 만드는 방법은 3가지가 있다.

  1. detach() :  특정 엔티티만 준영속 상태도 전환 
  2. clear() : 영속성 컨텍스트를 완전히 초기화
  3. close() : 영속성 컨텍스트를 종료

 

준영속 상태의 엔티티는 영속성 컨텍스트에서 분리된 상태이기 때문에 영속성 컨텍스트의 이점을 누릴 수 없는 상태라고 생각하면 된다. 비영속 상태와 거의 동일하지만, 영속 상태였다가 분리된 상태이기 때문에 식별자(ID) 값은 가지고 있다. 준영속 상태의 엔티티를 다시 영속 상태로 변경하려면 병합(merge( ))를 사용하면 된다.

 

TeamEntity teamEntity = new TeamEntity();
teamEntity.setName("Team1");

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

em.persist(teamEntity);

// 엔티티를 영속성 컨텍스트에서 분리하는 방법 1 : 특정 엔티티만 준영속 상태로 전환
em.detach(teamEntity);

// 엔티티를 영속성 컨텍스트에서 분리하는 방법 2 : 영속성 컨텍스트를 완전히 초기화
em.clear();

// 엔티티를 영속성 컨텍스트에서 분리하는 방법 3 : 영속성 컨텍스트를 종료
em.close();

 

 

Removed : 삭제 상태

객체를 삭제한 상태로 엔티티를 삭제할 때 사용된다. 커밋 시점에 삭제가 진행 된다.

// 삭제할 엔티티 조회
TeamEntity teamEntity = em.find(TeamEntity.class, "1");

// 엔티티 삭제
em.remove(teamEntity);

 

 

JPA를 처음 공부하게 되는 경우 새로운 용어들이 많다보니 이해가 쉽지 않다. 그렇기 때문에 개념을 여러번 보고, 실제로 코드도 작성하고 실행해보면서, 어떻게 동작하는지를 차근차근 보는 것을 추천한다.

반응형

댓글