반응형
Spring Data JPA 게시글은 대부분 인프런의 김영한님의 강의인 '실전! 스프링 데이터 JPA' 기반으로 내용을 정리했습니다.
JPA Hint & Lock
JPA Hint
JPA 쿼리 힌트(SQL 힌드가 아니라 JPA 구현체(하이버네이트)에게 제공하는 힌트이다.)
쿼리 힌트 사용
- MemberRepositoryTest.class
@Test
public void queryHint() {
Member member1 = memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
//Member findMember = memberRepository.findById(member1.getId()).get();
// 실무에서 get으로 바로 꺼내 쓰면 안된다.
Member findMember = memberRepository.findReadOnlyByUsername("member1");
findMember.setUsername("member2");
em.flush(); // 변경 감지 동작, update 쿼리 나감
}
JPA에는 변경 감지라는 기능이 있다. 그래서 find로 가져온 객체와 원본 객체를 비교해서 flush 하는 시점에 둘이 서로 값이 다를 경우 update 쿼리가 발생한다. 이런 기능이 편리하고 장점도 있지만 단점도 존재하긴 한다. 영속성 컨텍스트에서 가지고 있는 원본 객체가 값이 수정된 걸 어떻게 알까? 바로 find() 같이 객체를 가져오면 스냅샷을 따로 찍어놓는다. flush() 할 때 스냅샷과 원본이 다를 경우 update 쿼리를 날리는 것이다. 만약 단순히 조회한 다음에 화면에 뿌리는 기능이라면 위의 과정이 너무 쓸데없이 느껴진다. 왜냐면 조회 후 바로 뿌리는데 객체를 비교할 스냅샷을 굳이 만드는 과정조차 비용이기 때문이다.
그래서 하이버네이트에서는 단순히 조회만을 위한 기능을 제공한다. JPA에서는 그런 기능을 따로 제공하진 않고 힌트를 이용할 수 있도록 문을 열어두었다.
- MemberRepository.interface
@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
Member findReadOnlyByUsername(String username);
@Test
public void queryHint() {
Member member1 = memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
Member findMember = memberRepository.findReadOnlyByUsername("member1");
findMember.setUsername("member2");
em.flush();// 변경 감지 동작 안 함, update 쿼리 안나감
}
위와 같이 코드를 수정하면 find()해서 가져온 객체를 아무리 수정해도 update가 나가지 않는다. readOnly의 기능이 true면 내부 최적화를 알아서 해서 스냅샷을 따로 만들지 않는다. 그래서 수정이 일어나도 아무런 반응을 하지 않는다.
! readOnly로 얻을 수 있는 장점이 분명히 있지만 무분별하게 사용하면 안 된다. 전체 애플리케이션에서 조회 성능보다 더 복잡한 기능을 튜닝하는 것이 더 중요하다. 성능 테스트 후에 조회 성능에 문제가 있으면 적용하는 거지 미리 적용하거나 하는 건 비추
Lock
- MemberRepository.interface
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findLockByUsername(String username);
- MemberRepositoryTest.class
@Test
public void lock() {
//given
Member member1 = memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
//when
List<Member> result = memberRepository.findLockByUsername("member1");
}
select
member0_.member_id as member_i1_0_,
member0_.age as age2_0_,
member0_.team_id as team_id4_0_,
member0_.username as username3_0_
from
member member0_
where
member0_.username=? for update
Lock은 JPA에서 제공하는 기능이다. Lock은 내용이 어렵고 깊이 들어가야하니 김영한 님이 집필하신 JPA 책을 보고 공부하도록..! 여기서는 그냥 이런 게 있다 정도만 알면 된다.
반응형