[JPA] 영속성 컨텍스트(3) - 엔티티 조회

Done is better than perfect·2021년 8월 4일
0

JPA

목록 보기
5/12
post-thumbnail

엔티티 등록에 이은 엔티티 조회를 알아보자!
등록편에서 잠시 알아봤지만 다시 한번 기억을 되살려보자면..

우리가 JPA를 사용하여 데이터를 테이블에 저장하고싶을 때 사용했던 persist() 메소드는 호출 순간 곧바로 INSERT문을 DB에 날려주지 않는다.
엔티티 객체를 영속성 컨텍스트, 정확히는 영속성 컨텍스트 안에 1차 캐시에 넣어줄 뿐이다.

그렇다면 find()도 비슷하게 예상해볼 수 있지 않을까?
맞다. find() 메소드 역시 원하는 데이터를 곧장 DB에서 찾아오지 않는다.
먼저 1차캐시에 조회하고자 하는 엔티티가 있는지 찾아보고, 거기에 없다면 DB로 SELECT문을 날려 엔티티를 조회한다. 물론, 이 과정에서 1차캐시에도 저장한다.

아래 코드를 실행했을 때 어떻게 되는지 그림과 함께 살펴보고 결과를 예상해보자🤔

🎈 예제 코드 1

Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

// 1차 캐시에 저장됨
em.persist(member);

// 1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");

System.out.println("=========== END ===========");
tx.commit();


위 그림은 em.persist() 코드가 실행 된 이후이다. 이 그림이 이해가 되지 않는다면 전편을 다시 읽어보는게 좋을것이다! 여기서 특별히 한번 더 짚고 넘어갈 점은 반복해서 말했지만 아직 DB에 엔티티가 저장 된 것은 아니라는 점이다.

이 상태에서 em.find() 메소드가 실행된다면?


위 그림처럼 JPA는 먼저 1차캐시에서 내가 원하는 데이터가 있는지 찾아본다. 예제코드는 방금전에 Id로 사용했던 값을 그대로 조회에 이용하였으므로 1차캐시에는 내가 조회하고자 하는 엔티티가 저장되있다. 그러므로 DB로부터 데이터를 가져올 필요없이 1차캐시에서 가져오면 된다.

🎉 로그 1

=========== END ===========
Hibernate: 
    /* insert hellojpa.Member
        */ insert 
        into
            Member
            (name, id) 
        values
            (?, ?)

결과를 보면 이해가 더 잘 될것이다. commit() 메소드가 실행되기 전에는 INSERT도, SELECT도 전혀 실행되지 않는다. 1차 캐시에서만 데이터가 왔다갔다 했을 뿐, 결국 데이터 INSERT도 가장 마지막에 실행된다는 것을 확인할 수 있다.

위 예제를 조금 바꿔 데이터를 먼저 저장한 뒤, 그 상태에서 코드를 다시 작성하여 find() 메소드를 통해 데이터를 조회하면 어떻게 될까? 당연히 조회하고자 하는 데이터가 1차 캐시에 없기 때문에 find() 메소드가 실행되는 순간 곧바로 DB에 SELECT 쿼리를 날려 데이터를 조회한다.
(이런 부분은 직접 이것저것 수정해가며 테스트 해보면 좋을 것 같다.)


영속 컨텍스트의 이점

전편에서 언급했다시피 이런 1차 캐시의 존재로 인한 성능상의 이점이 있다.
위 예제만 살펴봐도 알수있듯 만약 1차 캐시가 없었다면, INSERT -> SELECT 차례대로 두번의 SQL이 실행되야 하지만, 1차 캐시 덕분에 한번의 SELECT문을 줄이며 동일한 결과를 얻을 수 있다.

또한 [동일성(identity) 보장] 이라는 특징이 있다.

MyBatis와 같은 SQL Mapper 방식으로 개발한다고 가정해보자!

동일한 데이터를 찾아오는 메소드를 두번 호출했을 때 각각이 반환하는 객체(아마도 VO 또는 DTO)는 동일한 객체일까?

정답은 NO, 메소드가 실행될 때마다 내부적으로는 new 키워드를 통한 새로운 객체의 생성이 이루어지고, 쿼리의 결과값들이 그 객체의 필드에 저장되기 때문에 사실상 동일한 값을 가진 객체라고는 말할 수 있지만, 객체 자체가 동일하다고 볼 수는 없다. 즉, 메모리 공간 상에 각자의 공간을 차지하고 있을것이다.. 물론 그 값들은 동일하겠지만 말이다.

하지만, JPA에서는 위의 그림처럼 객체의 동일성을 보장한다!
내가 아직 JPA의 내공이 부족하여 이 동일성을 보장한다는것이 어떠한 이점이 있고 중요한지는 아직 설명할 수 없다. 이것은 차차 공부하며 깨달음이 오는날 다시 설명하도록 하겠다.

이것으로 영속성 컨텍스트 3편을 마무리하며, 4편에서는 엔티티 수정 예제를 통해 영속성 컨텍스트의 남은 특징인 변경 감지(Dirty Checking)과 지연 로딩(Lazy Loading)에 대해 알아보겠다.

0개의 댓글