12. JPA Hint & Lock

민정·2022년 12월 13일
0

Spring Data JPA

목록 보기
12/17
post-thumbnail
post-custom-banner

JPA Hint란

JPA 구현체(= 하이버네이트)에게 제공하는 힌트

SQL 힌트 아님

ReadOnly 힌트

@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))

📁 MemberRepository

읽기만하는 함수 위에 @QueryHints 작성

@QueryHints(value = @QueryHint(name = "org.hibernate.readOnly", value = "true"))
// name과 value 모두 String : JPA가 하이버네이트에게 무엇이든지 넘길 수 있도록 구멍을 열어둠
Member findReadOnlyByUsername(String username);
// readOnly = true되어있으면 성능최적화해서 스냅샷을 만들지 않는다.

📁 MemberRepositoryTest

	@Test
    public void queryHint(){
        // given
        Member member1 = memberRepository.save(new Member("member1", 10));
        em.flush(); // 이때 실제로 DB에 쿼리 나감
        em.clear();

        // when
        Member findMember = memberRepository.findById(member1.getId()).get();
        findMember.setUsername("member2");

        em.flush(); // 변경감지 - update 쿼리 날라감
        em.clear();

        Member findMember_readOnly = memberRepository.findReadOnlyByUsername("member2");
        findMember_readOnly.setUsername("member3");


        em.flush(); // readOnly = true이면, 변경감지 체크를 안함 = update 쿼리 안날라감

    }

1) findById로 찾아온 member1의 이름을 member2로 변경하고 em.flush()를 하면

변경감지가 동작해 update 쿼리가 날라간다

2) @QueryHint를 적용해 readonly로 설정한 findReadOnlyByUsername함수를 사용해 member2를 조회한 뒤, member3로 이름을 변경하고 em.flush()를 하면

readonly로 @QueryHint를 통해 설정

변경을 했는지 비교할 대상인 스냅샷을 만들지 않아서 이름을 변경했어도, update 쿼리가 날라가지 않는다.

즉, readOnly = true면, 스냅샷을 만들지 않아서 변경감지 체크를 하지 않음.
=> Update 쿼리 날라가지 않음.

🤩 변경 감지의 원리

1차 캐시에 @Id, Entity, 스냅샷 총 3개의 컬럼이 존재

스냅샷 : 엔티티가 1차 캐시에 저장될 때, 저장되는 시점의 상태

트랜잭션이 커밋되는 시점에 엔티티와 스냅샷을 비교해서, 차이가 있다면 JPA는 이름 감지해 DB에 update 쿼리를 날림.

따라서! 커밋되기 전에 엔티티를 수정해 사용했다가, 커밋되는 시점에 다시 원상복구 시키면 update 쿼리가 실행되지 않음.

😢 JPA의 변경감지의 단점

변경을 확인하기 위해서는 원본이 있어야함.

내부적으로는 성능 최적화를 하겠지만, 결국 객체를 2개를 가지고 있어야함.
⇒ 메모리 사용 ⇒ 비용이 발생

나는 가져와서 변경 절대 안할거야. 그냥 조회만 할거야.
⇒ 그래도 영속성 컨텍스트에 가져오는 순간 변경할 수 있다는 가정하에 객체를 2개를 만들어둠.(원본변경했을때의 것)

✨ JPA Hint가 있는 이유

나는 100% 조회용으로만 쓸거야라고 하면, 이걸 최적화 할 수 있는 방법이 있음.

그 방법을 하이버네이트는 제공하는데 JPA 표준은 제공 안함.

⇒ ✨ 그래서 하이버네이트에게 힌트를 줄 수 있게한 것이 JPA Hint

성능 관련 이야기

readOnly = true 설정을 처음부터 다 깔고가는 것은 비추!

전체 애플리케이션 다 조회용으로만 쓰니까 다 readonly = true해야지라고 해봐야 얼마 최적화 안됨.

전체 100% 중에서 성능 떨어트리는 주요 요인복잡한 조회 쿼리 자체이기 때문!

사실 readonly같은 거 안 깔아도 이미 성능 잘 나온다!

=> 결국 성능테스트 해보시고, 아직 readonly 설정해서 해결될 것 같다 하면 그때 설정하면 된다.

=> readOnly로 해결 불가하다는 판단이 서면, 캐시와 같은 다른 방법을 사용하시는 것으로 결정하면 된다.


LOCK

  • DB에 select할 때, 다른애들은 이것에 손대지마! 라고 락을 걸 수 있음.

  • JPA도 LOCK을 지원

📁 MemberRepository

// Lock
    @Lock(LockModeType.PESSIMISTIC_WRITE)
    List<Member> findLockByUsername(String username);

✔ Test

	@Test
    public void lock(){
        // given
        Member member1 = new Member("member1", 10);
        memberRepository.save(member1);
        em.flush();
        em.clear();

        // when
        List<Member> result= memberRepository.findLockByUsername("member1");
    }


마지막에 for update
=> DB 방언 마다 동작 방식은 다름. 매뉴얼 참고!

사실 LOCK 이라는 주제 자체가 어려워서 JPA에서 LOCK이라는 것을 JPA가 이렇게 쉽게 사용할 수 있도록 제공하고 있다 정도로 소개

잘 사용하지는 않을 것,,,

강사님의 말씀

참고로 lock은 비즈니스마다 달라서 뭐가 정답이라고 할 순 없지만, 실시간 트래픽이 많은 서비스에서는 가급적 락을 거시면 안된다.


출처

김영한 강사님 - 인프런 실전! 스프링 데이터 JPA

https://ttl-blog.tistory.com/108

post-custom-banner

0개의 댓글