오늘 한 일
이전에 마주한 문제지만 까먹을까봐 정리해서 적어놓는다.
고양이(Cat
)와 주인(Owner
) 관계를 생각해보자.
주인은 고양이를 10마리씩 키우고 둘은 양방향 매핑이 되어있다고 가정한다.
다음과 같이 주인을 조회하는 코드를 실행한다면 고양이를 조회하는 쿼리가 10번 호출된다.
List<Owner> everyOwners = ownerRepository.findAll();
이런 현상은 FetchType.EAGER
라서 발생하는 것이 아니다. FetchType.LAZY
로 설정한다 한들 고양이의 이름을 조회하려 할 때 결국 동일하게 발생한다.
List<Owner> everyOwners = ownerRepository.findAll();
List<String> catNames = everyOwners.stream().flatMap(it -> it.getCats().stream().map(cat -> cat.getName())).collect(Collectors.toList());
FetchType을 변경하는 것은 단지 N+1 발생 시점을 연관관계 데이터를 사용하는 시점으로 미룰지, 아니면 초기 데이터 로드 시점에 가져오느냐에 차이만 있는 것이다.
해결방법은 직접 쿼리 작성, EntityGraph
등등 다양하다. 각각을 확인하고 알맞은 방법을 사용하자.
출처
https://incheol-jung.gitbook.io/docs/q-and-a/spring/n+1
JPA Entity 객체의 멤버 변수를 수정한 후 이러한 오류가 나타난다면 변수이름을 제대로 설정했는지 확인해보자.
@Id
String weekId; //올바른 객체명
//String WeekId; //올바르지 않은 객체명
만약 다른 엔티티와 관계가 있는 컬럼을 고쳤을 때 에러가 나타난다면 다음과 같이 @NamedEntityGraphs
를 확인해보자.
// String subjectWeekInfo;
String weekInfo; //위에 멤버변수 subjectWeekInfo를 weekInfo로 바꾼 상황
@NamedEntityGraphs({
@NamedEntityGraph(
name = "user-own-task",
attributeNodes = {
@NamedAttributeNode(value = "userTask", subgraph = "task-detail")
},
subgraphs = { @NamedSubgraph(
name = "task-detail",
// attributeNodes = { @NamedAttributeNode("subjectTaskInfo") }
attributeNodes = { @NamedAttributeNode("taskInfo") }
)
}
),
})