JPA 기본 - 영속성 관리

1. 영속성 컨텍스트


엔티티를 영구 저장하는 환경이라는 뜻으로 EntityManager을 생성하면 영속성 컨텍스트가 J2SE 환경에서는 1:1로 눈에 보이지 않게 생성된다고 보면 된다.(스프링 프레임워크 같은 컨테이너 환경에서는 엔티티 매니저와 영속성 컨텍스트가 N:1의 관계를 가진다.) 즉, 애플리케이션 계층과 DB계층 사이에 영속성 컨텍스트가 있다고 생각하면 된다. persist 한다고 해서 바로 db에 쿼리가 날려지는게 아니라 1차적으로 영속성 컨텍스트의 관리하에 들어가 있는 것이다.

EntityManager em // 주입 받았다고 가정

// Member은 Entity 클래스
Member member = new Member(); // member은 비영속 상태
em.persist(member); // member은 영속 상태
em.detach(member); //  준영속 상태, member을 영속성 컨텍스트에서 분리
em.remove(member); // 객체를 삭제한 상태


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


영속성 컨텍스트 안에는 1차 캐시와 쓰기 지연 SQL 저장소가 있다.

1차 캐시

그림2

영속성 컨텍스트 안에 있는 1차 캐시는 id, Entity, 스냅샷을 가지고 있다. persist로 Entity를 넣어주면 pk값이 id가되고 Entity는 Entity가 된다. 스냅샷은 후에 설명한다.

  • em.persist(member)을 하고 바로 em.find 했을 때
    • 바로 db에 select문을 날리는게 아니라 1차 캐시에서 먼저 탐색하고 있다면 1차 캐시에서 가져오고 없다면 db에 select문을 날린다. db에서 가져온 데이터는 1차 캐시에 저장되고 그것을 반환한다. 이후에 다시 find하게 되면 1차 캐시에서 가져온다.


동일성 보장

1차 캐시에서 가져오기 때문에 == 비교 즉, 동일성을 보장한다.


트랜잭션을 지원하는 쓰기 지연

앞서 persist를 하면 바로 db로 쿼리를 날리는게 아니라 영속성 컨텍스트 관리하에 들어간다고 했다. persist를 하면 먼저 영속성 컨텍스트 안에 있는 쓰기 지연 SQL 저장소로 쿼리문을 생성하여 저장해둔다. 그리고 commit 시점에 flush가 호출되면서 쿼리문을 다 날리고 commit이 된다. 설정으로 쿼리문을 모을 개수를 지정할 수도 있다.

엔티티 수정 변경 감지 dirty checking

em.find로 찾아온 엔티티는 영속성 컨텍스트의 관리하에 있고 1차 캐시 안에는 스냅샷이라는 정보가 있다. 스냅샷은 찾아오는 시점의 초기값이다. 만약 가져온 값들을 수정했다면 따로 persist, update 쿼리를 날려줄 필요가 없다. flush 되는 시점에 JPA가 1차 캐시안에 있는 Entity 값과 스냅샷 값을 비교하여 변경된 내용을 알아서 쿼리를 만들어 날려준다. 삭제도 마찬가지이다.

지연 로딩 Lazy Loading

쿼리를 나중에 날리는 건데 뒤에 강의에서 알아보도록 한다.

3. 플러시


영속성 컨텍스트의 변경내용을 데이터베이스에 반영하는 작업이라고 생각하면 된다. 보통 트랜잭션이 commit될 때 flush가 자동으로 호출된다. 그리고 작업을 마친 뒤에 최종적으로 commit한다. 플러시를 하게 되면 먼저 위에서 설명했던 dirty checking을 하여 필요한 쿼리문을 쓰기 지연 SQL 저장소에 등록한다. 그리고 쓰기 지연 SQL 저장소에 있는 쿼리들을 데이터베이스에 전송한다. 참고로 플러시를 한다고 해서 영속성 컨텍스트가 비워지는게 아니다.

플러시 하는 방법

  • em.flush() : 직접 호출
  • 트랜잭션 커밋 : 플러시 자동 호출
  • JPQL 쿼리 실행 : 쿼리 실행 전에 이전에 담겨있던 것 처리를 위해 플러시 자동 호출


4. 준영속 상태


1차 캐시에 올라간 상태를 영속 상태라고 보면 된다. persist하거나 find로 가져오면 1차 캐시에 등록된다고 보면 된다. 1차 캐시에 올라가 있는 엔티티를 영속성 컨텍스트의 관리에서 빼내면 준영속 상태가 된다. 준영속 상태가 되면 1차 캐시에 없는 엔티티이기 때문에 변경 감지등 1차 캐시에 있었을 때의 이점을 모두 잃게 된다.

준영속 상태로 만들기

  • em.detach(entity) : 특정 엔티티를 준 영속 상태로 전환
  • em.clear() : 영속성 컨텍스트 초기화
  • em.close() : 영속성 컨텍스트 종료



본 포스팅은 인프런 김영한님의 ‘자바 ORM 표준 JPA 프로그래밍 - 기본편’ 강의를 듣고 정리한 내용을 바탕으로 복습을 위해 작성하였습니다. [강의 링크]


© 2021. By Backtony