JPA Hint & Lock
JPA Hint
SQL 힌트가 아니라 JPQ 구현체에게 제공하는 힌트
public interface MemberRepository extends JpaRepository<Member, Long> {
@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
Member findReadOnlyByUsername(String username);
}@SpringBootTest
@Transactional
@Rollback(value = false)
class MemberRepositoryTest {
@Test
public void queryHint() throws Exception {
memberRepository.save(new Member("member1", 10));
// DB에 동기화
em.flush();
// 영속성 컨텍스트 초기화
em.clear();
// 영속성 컨텍스트를 초기화 했으니 무조건 DB에 쿼리를 날린다.
Member member = memberRepository.findReadOnlyByUsername("member1");
member.setUsername("member2");
// 더티 체킹이 반영되지 않는다.
em.flush();
}
}insert into member (age, team_id, username, member_id)
values (10, NULL, 'member1', 1);
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 = 'member1';더티 체킹은 원본과 수정본을 둘 다 메모리에 들고 있어야 하고 체크하는 과정도 필요하기 때문에 비용이 든다.
단지 조회만 하고 끝내고 싶어도 find()를 하는 순간 스냅샷을 떠놓게 된다.
readOnly 힌트를 넘기면 select만 나가고 update는 나가지 않는다.
성능은 복잡한 쿼리 때문이지 readOnly를 적용하지 않아서는 거의 없다.
성능 테스트를 해보고 정말 이점이 있는 곳에서 사용한다.
Lock
public interface MemberRepository extends JpaRepository<Member, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Member> findByUsername(String name);
}@SpringBootTest
@Transactional
@Rollback(value = false)
class MemberRepositoryTest {
@Test
public void lock() {
memberRepository.save(new Member("member1", 10));
em.flush();
em.clear();
List<Member> members = memberRepository.findByUsername("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 = 'member1' for update;락을 적용할 수 있다.
for update
데이터를 수정하려고 select 하는 중이니 다른 사람은 데이터에 손대지 말라는 뜻
실시간 트래픽이 많은 곳에 락을 걸면 위험하다.
Last updated
Was this helpful?