작성
·
213
·
수정됨
0
@Test @Transactional
public void 테스트() throws Exception{
Member member1 = new Member("member1", 10);
Team teamA = new Team("teamA");
member1.changeTeam(teamA);
teamRepository.save(teamA);
//member <- cascade persist
em.flush();
em.clear();
memberRepository.findByAge(10); // SELECT 1번
memberRepository.findByUsername("member1"); // SELECT 2번
memberRepository.findById(member1.getId()); // 영속성 컨텍스트에 PK값이 존재
}
쿼리 조회 메서드 실행 시 JPQL 이 동작하여 flush 후 DB에 바로 쿼리가 날라가고 가져온 것이 영속성 컨텍스트에 저장된다고 알고 있습니다.
만약에 save(new Member(member1, 10)); 후에
save한 엔티티 대상을 조회하기 위한 findByAge (where = 10) , findByUsername (where = member1) 을 순서 대로 쿼리 메서드 호출을 하였을 때 조회 쿼리가 결국 같은 엔티티를 조회하기 위함인데 SELECT 쿼리문이 2번 나갔습니다.
2번 나간 이유가
findByAge 호출 후에 findByUsername 호출 시 1차 캐시에서 비교할려면은 무조건 id값이랑 비교가 가능하기
때문인지 궁금합니다.
답변 2
1
안녕하세요. 이승훈님, 공식 서포터즈 코즈위버입니다.
셀렉트 쿼리가 두 번 실행된 이유는, 검색 조건인 id와 age가 키가 아니기 때문입니다. 키가 아닌값으로 검색을 하기에 실제 데이터베이스에서 데이터를 조회해야만 정확한 결과를 알 수 있습니다. 그래서 각각 쿼리가 두 번 실행되어 결과를 영속성컨텍스트에 담게 되고, 이후에 id 를 이용해 다시 조회할 때에는 영속성컨텍스트내에 해당 아이디를 가진 엔터티가 있으므로 셀렉트 쿼리가 발생하지 않습니다.
감사합니다.
키 라는 것은 코드로 말하자면 @Id 로 지정한 필드를 말합니다 :)
이론적으론 어떤 엔터티를 식별하는 고유한 값을 말합니다.
회원(Member) 엔터티에서 이름(name)과 나이(age)는 중복 가능한 값으로 유일하지 않기에 키로 사용할 수 없는 속성 입니다.
감사합니다 :)
1
안녕하세요 이승훈 님, 인프런 AI 인턴이에요.
해당 코드를 보면, save 메서드를 사용하여 Member 엔티티를 저장한 후에 findByAge와 findByUsername 메서드를 순서대로 호출하였습니다. 이 때, 별도의 영속성 컨텍스트 플러시(em.flush()
) 또는 영속성 컨텍스트를 초기화(em.clear()
)한 후에 조회 쿼리를 실행하였습니다.
JPQL 쿼리 실행 시, 영속성 컨텍스트에 저장된 엔티티 중에서 매칭하는 엔티티를 찾아 최대한 데이터베이스에 쿼리를 날리지 않도록 최적화합니다. 따라서, findByAge 메서드를 호출하여 나이가 10인 Member를 찾을 때, 영속성 컨텍스트에서는 이미 이전에 저장된 엔티티를 찾아 반환합니다. 그 후, findByUsername 메서드를 호출하여 username이 “member1”인 Member를 찾을 때에도 역시 이전에 영속성 컨텍스트에 저장된 엔티티를 찾아 반환합니다. 따라서, 조회 쿼리가 한 번만 실행되는 것이 정상적인 동작입니다.
만약 조회 결과가 인메모리에서 비교되는 것이 아니라 데이터베이스에서 비교된다면, SELECT 쿼리가 2번 실행될 수도 있습니다. 이는 JPA 구현체에 따라 다를 수 있으며, 성능 최적화를 위한 캐시나 인덱스 설정 등을 고려하여 적절한 방법으로 진행되기 때문입니다.
I hope this helps! 좋은 하루 되세요.
답변감사합니다.
혹시 검색 조건인 id와 age가 키가 아니기 때문입니다. -> 이 부분 id가 username이 아닌가요?
나머지 설명은 제가 추후에 생각된 생각과 같습니다.