Entity Graph

JIWOO YUN·2023년 10월 18일
0

SpringDataJPA

목록 보기
4/4
post-custom-banner

Entity Graph

기본적으로 가져오는 값이 Lazy로 설정되있을경우 -> 값이 필요할때 따로 조회해서 가져온다.

  • 프록시로 채워져있음.

    ==> 따라서 이 값이 필요할때마다 조회 쿼리를 보내게 됨(N+1문제 가 발생됨.)

JPA에서는 fetch join을 통해서 해결함.

  • 한번에 필요한 내용을 다끌고와서 가짜프록시 객체가 아닌 진짜 객체가 들어있게됨.
  • 조회의 주체가 되는 Entity 이외에 Fetch join이 걸린 연관 Entity도 함께 SELECT 하여 모두 영속화시킴.
  • fetch join을 쓰려면 JPQL이 필수로 필요하다.

이걸 해결해주는게 EntityGraph

@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();

-> fetch join의 간편버전이다.


JPA Hint & Lock

JPA 힌트

  • JPA 구현체에게 제공하는 힌트(SQL 힌트 아님.)

힌트에 대해서 얘기하기전에 다른 이야기를 해보자.

member id 가 1인 친구의 이름을 member2로 바꾸는 경우 -> em.flush()를 통해서 값의 변경이 있다는 것을 확인하고 update쿼리가 나가게 되어서 값이 변경이 된다.

  • 변경 감지를 하기위해서는 원본이 존재해야함. -> 2개의 객체를 관리하게됨. -> 메모리를 더먹게됨.
  • 변경 목적이 아니라 조회만 한다해도 객체를 가져올 경우 원본을 만들어둔다.

이 문제를 해결하기 위해서 사용되는게 JPA 힌트다.

@QueryHints(value = @QueryHint(name= "org.hibernate.readOnly",value = "true"))
Member findReadOnlyByUsername(String username);

쿼리 힌트를 통해서 readOnly로만 하겠다고 알려주게될경우

@Test
public void queryHint(){

    Member member1 = new Member("member1", 10);
    memberRepository.save(member1);
    em.flush();
    em.clear();


    Member byId = memberRepository.findReadOnlyByUsername("member1");
    byId.setUsername("member2");

    em.flush();

}

위와 같은 테스트를 돌리게 된다해도 setUsername을 무시하게됨.(readOnly로만 되기 때문에 변경감지를 체크하지 않는다.) - 스냅샷이 존재하지 않음.

스냅샷 ?


엔티티가 1차 캐시에 저장될 때, 저장되는 시점의 상태를 스냅샷으로 만들어 1차 캐시에 보관합니다.

트랜잭션이 커밋되는 시점에 엔티티와 스냅샷을 비교하는데, 이때 만약 엔티티가 변경되었다면 당연히 스냅샷과 차이가 있을 것이고, JPA는 이를 감지하여 DB에 반영합니다.

중요한 것은 "커밋되는 시점"에 "엔티티와 스냅샷을 비교"한다는 것입니다.

따라서 커밋되기 전에 엔티티를 수정하여 사용하였다가, 커밋되는 시점에 다시 원상복구 시키면 update 쿼리가 실행되지 않습니다

profile
열심히하자
post-custom-banner

0개의 댓글