기본적으로 가져오는 값이 Lazy로 설정되있을경우 -> 값이 필요할때 따로 조회해서 가져온다.
프록시로 채워져있음.
==> 따라서 이 값이 필요할때마다 조회 쿼리를 보내게 됨(N+1문제 가 발생됨.)
JPA에서는 fetch join을 통해서 해결함.
이걸 해결해주는게 EntityGraph
@Override
@EntityGraph(attributePaths = {"team"})
List<Member> findAll();
-> fetch join의 간편버전이다.
JPA Hint & Lock
JPA 힌트
힌트에 대해서 얘기하기전에 다른 이야기를 해보자.
member id 가 1인 친구의 이름을 member2로 바꾸는 경우 -> em.flush()를 통해서 값의 변경이 있다는 것을 확인하고 update쿼리가 나가게 되어서 값이 변경이 된다.
이 문제를 해결하기 위해서 사용되는게 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 쿼리가 실행되지 않습니다