https://cheese10yun.github.io/jpa-jpql/

JPQL 조회 방식

findById() 같은 경우는 영속성 컨텍스트를 먼저 찾고 영속성 컨텍스트에 해당 엔티티가 있으면 그 값을 바로 리턴합니다. 이를 1차 캐시라고 말합니다. 반면 JPQL은 영속성성 컨텍스트를 먼저 조회하지 않고 데이터베이스에 Query 하여 결과를 가져옵니다. 그리고 아래와 같은 흐름으로 영속성 컨텍스트를 저장을 시도합니다.

  1. JPQL을 호출하면 데이터베이스에 우선적으로 조회한다.
  2. 조회한 값을 영속성 컨텍스트에 저장을 시도한다.
  3. 저장을 시도할 때 해당 데이터가 이미 영속성 컨텍스트에 존재하는 경우(영속성 컨텍스트에서는 식별자 값으로 식별) 데이터베이스에서 조회한 신규 데이터를 버린다.

JPQL 조회 방식 테스트

해당 코드는 단순합니다. Team은 N 개의 Member를 가질 수 있는 구조입니다. TeamRepository의 findFetchJoinBy 메서드는 단순히 팀 이름으로 Fetch Join 해서 해당 Team에 속한 모든 Member를 조회하는 JPQL 코드입니다. JPQL이 위에서 설명한 방식대로 동작하는지 아래 테스트 코드로 확인해보겠습니다.

해당 테스트는 실패합니다. teamA를 저장하고, member1, member2에 각각 teamA를 저장했습니다. 그리고 Fetch Join을 통해서 아래 SQL 문으로 데이터를 조회합니다.

올바르게 데이터가 저장되고, 조회 쿼리 또한 문제가 없는데 해당 테스트는 실패합니다.

왜 테스트가 실패하는 것일까 ?

주의! Team 객체를 저장할 때 member1, member2를 members 컬렉션에 저장하는 양방향 편의 메서드를 작성하면 해당 테스트는 실패하지 않습니다. JPQL의 동작 방식을 테스트해보기 위해서 작성했습니다.

영속성 컨텍스트와 데이터베이스 흐름을 자세히 살펴 보겠습니다.

  1. teamA, member1, memeber2를 영속화를 위해서 persist 메서드를 통해서 영속성 컨텍스트에 저장
  2. 데이터베이스에 영구적으로 저장하기 위해서 flush, commit을 진행
  3. findFetchJoinBy를 통해서 조회를 진행, JPQL은 영속성 컨텍스트를 먼저 들리는 것이 아니라 데이터베이스로 조회