Backend

[JPA]영속성 관리 : 내부 동작 방식

연_우리 2022. 2. 21. 00:40
반응형

목차

     

     

    영속성 컨텍스트?

    영속성 컨텍스트는 논리적인 개념이다.

    엔티티매니저를 통해서 영속성 컨텍스트에 접근한다.

     

     - J2EE 같은 환경

       엔티티매니저와 영속성 컨텍스트가 1:1 관계.

       엔티티매니저 안에 영속성 컨텍스트가 1개 있다.

     

     - 스프링 프레임워크 같은 컨테이너 환경 

       엔티티매니저와 영속성 컨텍스트가 1:N 관계.

       여러 엔티티매니저를 통해 1개의 영속성 컨텍스트에 접근한다.

     

     

     

    영속성 컨텍스트 구조

    자바 ORM 표준 JPA 프로그래밍 - 기본편

    1. Map형태의 1차 캐시 공간 : transaction.commit()전까지 값을 모아놓는다.

    2. 쓰기지연 SQL저장소 : transaction.commit()전까지 SQL문들을 모아놓는다.

     

    em.persist(memberA) 하면

     - insert SQL문을 쓰기지연 SQL저장소에 저장하고,

     - memberA엔티티를 1차 캐시에 저장한다.

     - memberA엔티티의 스냅샷을 만들어서 보관한다. (나중에 스냅샷과 엔티티를 비교하여 변경된 곳을 체킹한다)

     

    이때, @id값은 DB의 id값과 같다. 

    엔티티의 @GeneratedValue 전략이 identity인 경우, DB에 저장되기 전까지는 id가 null이기 때문에

    JPA는 @GeneratedValue전략이 identity일때만 em.persist()를 하면 바로 insert SQL문을 DB에 전송하고

    받은 id값을 1차 캐시의 키로 사용한다.

     

     

     

    영속성 컨텍스트의 이점

    1. 1차 캐시에서 조회

        em.persist(member)하면 member가 1차 캐시에 저장되고

        em.find(member)하면 1차 캐치에 저장된 member를 반환해준다.

        => DB까지 가지 않아도 값을 반환해줄 수 있다!

     

        em.find(member2)했을 때 1차 캐시에 없다면, 그때 DB에서 조회한다.

        DB에서 조회한 결과를 1차 캐시에 저장하고, 1차 캐시에 저장된 member2를 반환해준다.

     

        (하지만, 엔티티매니저는 각 요청마다 생성되었다가 삭제된다. 요청이 살아있을 때에만 1차 캐시의 이점을 누릴 수 있다)

     

    2. 동일성 (identity) 보장

        List<Member> memberList = new ArrayList<>();

        memberList.add(memberA);

        memberList.add(memberA);

        memberList.get(0) == memberList.get(1);

        => 객체지향 리스트에서 같은 값을 저장한 것은 같다고 본다. (같은 참조이기때문에)

     

        Member memberA = em.find(Member.class, memberA.getId());

        Member memberB = em.find(Member.class, memberA.getId());

        memberA == memberB;

        => 같은 식별자로 가져온 값이니 같다고 판단한다.

     

    3. 트랜잭션을 지원하는 쓰기 지연 (Transactional write-behind)

        em.persist(membr)는 즉시 insert SQL문을 DB에 전송하지 않는다.

        쿼리를 영속성 컨텍스트의 쓰기지연 SQL저장소에 쌓아놓고 있다가,

        transaction.commit()하는 순간 모아놓은 쿼리를 DB에 보낸다 (일종의 버퍼)

     

    4. 변경 감지 (Dirty Checking)

        엔티티를 1차 캐시에 저장할 때, 엔티티를 똑같이 복사한 스냅샷을 저장한다.

        엔티티의 값을 수정하게되면 스냅샷과 달라지게되니, 이것을 확인하여 JPA가 알아서 Update SQL문을 생성한다.

     

        객체를 수정할때와 유사하다.

        List<Member> memberList = new ArrayList<>();

        Member member = memberList.get(0);

        member.changeName("memberZ");

        //memberList.add(member);   => 수정한 객체를 다시 리스트에 저장하지 않는 것처럼

     

        Member findMember = em.find(Member.class, "memberA");

        findMember.changeName("memberZ");   => 값만 수정해주면 된다.

     

    5. 지연로딩 (Lazy Loading)

     

     

     

    엔티티의 생명주기

    1. 비영속 (new/transient)

        객체가 처음 생성된 상태. 영속성 컨텍스트와 전혀 관계없는 상태.

        Member member = new Member();

        member.setId("member1");

     

    2. 영속 (managed)

        영속성 컨텍스트에 관리되는 상태

        em.persist(member) : 엔티티매니저를 통해 영속성 컨텍스트에 객체를 저장한다.

        em.find(member) : JPA는 1차 캐시를 먼저 살피고, 1차 캐시에 member가 없다면 DB에서 조회한다. 
                                 DB에 조회한 결과를 1차 캐시에 먼저 저장하고, 1차 캐시의 값을 다시 반환해준다.

                                 따라서 em.find()할때도 영속성 컨텍스트에 데이터가 올라가게된다.

     

    3. 준영속 (detached)

        영속성 컨텍스트에서 분리된 상태

        em.detach(member) : 엔티티매니저를 통해 영속성 컨텍스트에서 member를 삭제한다.

        em.clear() : 엔티티매니저를 통해 영속성 컨텍스트의 내용을 모두 삭제한다.

     

    4. 삭제 (removed)

        삭제된 상태

        em.remove(member) : 실제 DB에서 member에 해당되는 내용을 삭제한다.

     

     

     

     

    자바 ORM 표준 JPA 프로그래밍 - 기본편
    반응형
    • 네이버 블러그 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 구글 플러스 공유하기
    • 카카오톡 공유하기