지금까지 굉장히 잘못된 지식을 가지고 있었다.
이 글을 한 줄로 요약하자면
1차 캐시는 PK가 아니면 작동하지 않는다!!!!
JPA는 캐시가 존재한다. 캐시를 두는게, DB에 쿼리를 날리고, 다시 받아오는 오버헤드보다 훨 낫기 때문이다.
나는 지금까지 한번 조회한 엔티티는 트랜잭션이 끝나기 전까지 무조건 1차 캐시에 남고, 어떤 쿼리의 조회 대상이 캐시에 존재하면 쿼리없이 가져온다 라고생각했다
반은 맞고 반은 틀렸다. 엔티티를 조회하면 트랜잭션이 종료되기 전까지 1차 캐시에 남는건 맞다. 그렇지만 , PK를 기반으로 조회하지 않는다면 무조건 쿼리가 날아간다
@EntityGraph, @Cacheable은 제외하고 서술하겠다.
- 캐시에 저장되는건 커스텀 쿼리(JPQL)을 사용해도 문제 없이 1차 캐시에 저장된다.
- 단, 캐시에서 값을 가져오는건 PK를 기반으로한 find (entity manager를 쓸때 find() 메서드 혹은 data-jpa의 findById)에서만 작동한다.
- select c from Comment c where c.id = :paramId 와 같은 PK기반 JPQL도 무조건 쿼리가 날아간다. (em.createQuery 가 호출된다. em.find가 아니라!)
- 트랜잭션이 종료되거나, flush()될 경우 캐시는 초기화된다. (메서드나 서비스 클래스 자체에
@Transactional
을 붙임을 생각해보자.)- 당연한 이야기지만 PK 기반 find 조회를 하더라도, 처음 불러오는 엔티티면 쿼리가 날아간다.
2번,3번 조건을 모르고 있어서 세시간이 날아갔다. join fetch
써서 로드 한번에 한 엔티티인데 계속 쿼리가 두번 날아가더라. 너무 고치고싶어서 디버깅 하다가 다른곳에서 발생한 순환 참조만 찾아서 고쳤다.
미래의 나는 공식문서를 제발 읽고 쓰길..