[Spring Data JPA] JPA Hint & Lock
@Test
public void queryHint() {
//given
Member member1 = memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
//when
Member findMember = memberRepository.findById(member1.getId()).get();
findMember.setUsername("member2");
em.flush();
}
해당 테스트의 경우 member1의 이름을 member2로 바꾸는 테스트이다.
member1을 영속성 컨텍스트의 1차캐시에 담고 스냅샷에 현재의 상태를 저장해둔다
이후 username을 바꾸게되면 스냅샷과 1차캐시의 값이 다른 것을 인지하게되고
query 로 업데이트가 나가게 되는 것이다.
하지만 만약 조회만 하는 로직을 짰다면?
굳이 1차캐시와 스냅샷을 비교하는 과정이 필요 없어진다. 이러한 리소스를 없애는 것이 JPA Hint이다.
예를 들어 읽기 전용으로 쓸때이다.
@QueryHints(value = @QueryHint( name = "org.hibernate.readOnly",value = "true"))
Member findReadOnlyByUsername(String username);
@Test
public void queryHint() {
//given
Member member1 = memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
//when
Member findMember = memberRepository.findReadOnlyByUsername("member1");
findMember.setUsername("member2");
em.flush();
}
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=?
결과 코드를 보면
findMember.setUsername("member2");
1차캐시를 건드렸음에도 불구하고 readOnly옵션을 주었기때문에 읽기전용으로 최적화가 된다.
즉스냅샷이 안 만들어지고 변경 감지기능을 안 쓰는 것이다.
따라서 Update문도 안 나간다.
여담: 읽기전용 쿼리를 위해 해당 힌트를 주는 것은 좋긴한데 실제로 서비스에서 부하를 크게 주는 곳은 복잡한 쿼리다.
즉 그다지 부하를 주지도 않는 곳에 이렇게 까지 공을 들여 모든 읽기전용쿼리에 해당옵션을 줄 필요가 있을까 생각할 필요가 있다.
실전! 스프링 데이터 JPA - 인프런 | 강의
스프링 데이터 JPA는 기존의 한계를 넘어 마치 마법처럼 리포지토리에 구현 클래스 없이 인터페이스만으로 개발을 완료할 수 있습니다. 그리고 반복 개발해온 기본 CRUD 기능도 모두 제공합니다.
www.inflearn.com
✔Lock은 다음과 같이 사용한다.
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findLockByUsername(String username);
락의 기능
https://www.baeldung.com/jpa-pessimistic-locking
Pessimistic Locking in JPA | Baeldung
A quick guide to using pessimistic locking in JPA
www.baeldung.com