Programming/JAVA

JPA - 영속성 컨텍스트(persistence context) 파헤쳐보기

긍정왕웹서퍼 2022. 12. 28. 23:59
728x90

목차

     

     

     

     

    https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-%EC%8B%A4%EC%A0%84

    개요

    지난 포스팅에선 JPA의 큰 개념과 이론에 대해 알아보았습니다. 이번엔 JPA에서 가장 중요한 패러다임인
    영속성 컨텍스트 (Persistence Context) 에 대해 알아보겠습니다. JPA를 공부하다 보면 자주 마주하는 단어가
    영속성 컨텍스트인데, 저는 아무리 봐도 잘 머리에 남지가 않았습니다. 애매모호하게 알고만 있던 개념이다 보니 그런거 같아서

    한번 정리하고 가면 좋을거 같습니다.

     

     

     

    Persistence Context

    JPA가 데이터를 관리하기 위해 엔티티를 사용해서 데이터베이스에서 데이터를 매핑하고 이를 저장해야하며,
    이때 필요한 환경을 영속성 컨텍스트라고 합니다. 좀 더 간단하게 말하자면 "엔티티를 영구히 저장하기 위한 환경" 이라 하며
    엔티티를 조작하기 위해 EntityManager를 통해서 영속성 컨텍스트에 접근할 수 있습니다. 

    기본적으로 엔티티매니저와 영속성 컨텍스트는 1:1 관계였으나, Spring Framework 같은 컨테이너 환경에서는 N:1 관계가 되었습니다.

     

     

     

    Life Cycle

    영속성 컨텍스트에도 역시 트랜잭션이 이루어졌을 때 생명주기가 존재한다. 

    1. 비영속(new / transient) 상태 : 영속성 컨텍스트와 아직 관계가 없는 새로운 상태를 의미합니다. 
    2. 영속(managed) 상태 : 영속성 컨텍스트에 의해 관리되고 있는 상태입니다.  
    3. 준영속(detached) 상태 : 영속성 컨텍스트에 저장되었다가 분리된(끊어진) 상태입니다.
    4. 삭제(removed) 상태 : 영속성 컨텍스트에서 완전히 지워진 상태입니다. 

     

     

    사용 이점 

    영속성 컨텍스트를 사용하는 것의 이점(장점)은 무엇일까??

    • 1차 캐시(cache) 를 사용한다 : 한번 조회한 값을 보관하고 있다가 동일한 조회를 한다면 데이터베이스가 아닌 캐시에서 가져온다..
    • 동일성(identity) 을 보장한다 : 같은 데이터를 여러번 호출해도 동일한 데이터임을 보장한다. 
    • 트랜잭션을 지원하는 쓰기 지연(transactional write-behind) : write를 모아서 보관해뒀다가 한번에 commit을 통해 등록
    • 엔티티 상태(값) 변경 감지(dirty checking) : update 시 데이터가 변경된게 있다면 이를 JPA가 인지하여 update 쿼리를 생성
    • 지연 로딩(lazy loading) : 실제 사용하기 전까지 기다렸다가 사용 시점에 맞춰서 데이터를 가져오는 것이며 이때
      가짜 객체(프록시 객체) 가 필요합니다. 

     

    프록시 객체

    지연 로딩에서 실제 객체를 가져오는 대신 가짜 객체를 만들어 사용한다고 했습니다.  왜 이런방식으로 사용할까요? 이는 Proxy 라는 개념에 대해 먼저 알아야합니다. 프로그래밍에서 Proxy는 '대신하다' 라는 의미의 단어 그대로 어떤 행위, 혹은 객체를 대신하기 위한 개념으로서 다양한 프로그래밍언어, 프레임워크등에서 사용되곤 합니다. 여기서 JPA(하이버네이트)는 지연 로딩을 구현할 때 사용하게 되는데요

    지연 로딩을 하려면 엔티티의 실제로 사용하기 전까지 기다릴 때 데이터를 보관할 곳이 필요합니다.

    이때 JPA(하이버네이트)는 프록시(Proxy) 객체를  주입하여 실제 객체가 있는 것 처럼 동작하도록 합니다. 

     

    실제 객체를 대신하기 위해 프록시 객체는 실제 객체를 상속받은 타입을 가지고 실제 객채에 대한 참조를 보관하여 프록시 객체의 메서드를 

    호출 했을 때 실제 객체의 메서드를 호출하여 실제 객체 타입에 문제없이 호환되어 사용할 수 있습니다.  이 때문에 JPA의 엔티티를 생성하는 규칙이 생겼는데 '기본 생성자는 최소 protected 접근 제한자를 가져야 한다.' 와 '엔티티 클래스는 final로 정의할 수 없다' 입니다.

     

    프록시 객체 초기화

    초기화를 위해선 지연 로딩시점이 끝나고 실제 객체의 메서드를 호출할 때 데이터베이스를 조회해서 참조값을 채우게 되고 이를 프록시 객체의 초기화한다고 합니다. 조회(select)를 통해 데이터를 가져올 때 초기화한다고 했습니다. 이 때, 프록시가 실제 객체를 참조하게 되는
    것이지 프록시가 실제 객체로 바뀌지 않는다는 것을 알아야합니다. 그리고 프록시를 초기화하지 못하는 경우도 있는데, 이는 프록시가 초기화 될 때 영속성 컨텍스트의 도움을 받습니다. 그렇기에 영속성 컨텍스트의 상태가 준영속 상태여서 프록시의 상태를 관리할 수 없게 된다면 프록시와 완련된 에러인 LazyInitializationException 을 발생하게 됩니다. 

     

     

     

     

     

    참조 https://tecoble.techcourse.co.kr/post/2022-10-17-jpa-hibernate-proxy/