JPA : 객체의 영속성 컨텍스트 참조


    영속성 컨텍스트에 엔티티가 남아있을 경우

    @Test
    @Rollback(value = false)
    void 이메일로_아이디찾기_성공() {
    
        Member newMember = Member.createNewMember("abc", "abcd", "abcde", "abcde@naver.com");
        em.persist(newMember);
    
        Member findByMember = memberService.findJoinIdByEmail("abcde@naver.com");
    
        log.info("new Member = {}", System.identityHashCode(newMember));
        log.info("findByMember = {}", System.identityHashCode(findByMember));
    
        Assertions.assertThat(newMember).isEqualTo(findByMember);
    }

    영속성 컨텍스트에 엔티티를 넣고, 이후에 다시 한번 DB에서 동일한 엔티티 조회한다. PK값으로 조회하게 되면, 영속성 컨텍스트에서 PK 값으로 찾아보고 없으면 DB에 Select 쿼리를 보낸다. 그렇지만 이번에는 엔티티의 필드값으로 찾았기 때문에 PK가 뭔지 모른다. 따라서, DB에 먼저 SELECT 쿼리를 보낸다.

    SELECT 쿼리를 보내서 엔티티를 찾아온다. 이 때, 영속성 컨텍스트에는 이미 동일한 PK를 가진 엔티티가 관리되고 있다. 따라서, find 쿼리의 결과값을 받는 객체는 영속성 컨텍스트에 있는 참조를 가리키게 된다. 

    따라서 실행 결과, newMember와 FindMember의 주소값을 찍어보면 다음과 같이 동일한 객체를 가리키는 것을 볼 수 있다. 왜냐하면 영속성 컨텍스트에서 PK로 관리하고 있기 때문이다.

     


    영속성 컨텍스트에 엔티티가 없을 경우

    @Test
    @Rollback(value = false)
    void 이메일로_아이디찾기_성공() {
    
        Member newMember = Member.createNewMember("abc", "abcd", "abcde", "abcde@naver.com");
        em.persist(newMember);
    
    	// 영속성 컨텍스트 초기화
        em.flush();
        em.clear();
    
    	Member findByMember = memberService.findJoinIdByEmail("abcde@naver.com");
    
        log.info("new Member = {}", System.identityHashCode(newMember));
        log.info("findByMember = {}", System.identityHashCode(findByMember));
    
        Assertions.assertThat(newMember).isEqualTo(findByMember);
    }

    위와 동일한 코드지만, 영속성 컨텍스트를 초기화하는 커맨드를 넣어주었다. 이후에 조회를 하면 동일하게 Select 쿼리는 나가게 된다. 그런데 앞의 경우와 상황이 달라졌다. 앞의 테스트 코드에서는 newMember가 영속성 컨텍스트에 엔티티로서 저장이 되어있었다. 그런데 이번에는 em.clear()를 통해 newMember는 영속성 컨텍스트에서 관리가 되지 않았다.

    이런 상황에 E-mail 값으로 찾아온 findMember는 영속성 컨텍스트에 등록이 된다. 이 때, findMember만 새로 불러져서 객체가 만들어져 등록된다. 이렇게 되면, findMember는 새롭게 객체가 만들어지기 때문에 new Member와 다른 주소값을 가진다. 왜냐하면 전혀 다른 객체이기 때문이다.

    그렇지만 new Member와 findMember가 가지는 필드는 동일하다. new Member는 영속성 컨텍스트에 처음에 들어가는 시점에 @GeneratedValue를 통해 PK값을 가지게 되고, findMember는 DB에서 가져온 값을 그대로 퍼올렸기 때문이다.

    이 뿐만 아니라, 당연히 필드 값도 모두 동일하다.

     


    정리

    • DB에서 찾아온 엔티티가 이미 영속성 컨텍스트에서 관리되고 있는 엔티티라면, 다른 객체라도 동일한 엔티티를 참조한다.
      • 준영속화 된 엔티티와 영속성 컨텍스트에서 관리하고 있는 엔티티의 PK같다고 하더라도, 다른 객체다(다른 참조를 가진다)
    • 엔티티는 em.persist를 하는 시점에 @GeneratedValue를 통해 PK값을 받는다.

     

     

    댓글

    Designed by JB FACTORY