N+1 문제를 해결하기 위해서 fetchJoin을 사용하여 해결해 주는 과정에서 yata와 연결된 yatamember 중 수락된 yatamember를 계산해서 보여줄 필요가 있었는데 수가 비정상적으로 많게 나오는 문제가 발생하였다.
@OneToMany의 경우 카테시안 곱 문제나
여러개의 fetchJoin을 사용할 경우 발생하는 MultipleBagFetchException을 고려해줘야한다.
카테시안 곱
발생가능한 모든 경우의 수의 행이 조회되는 것
즉, N 개의 행을 갖진 테이블과 M개의 행을 가진 테이블의 카타시안 곱은 N * M이 되는 것
한번의 쿼리로 yataMember를 조회할 때 관련되어 있는 yata까지 한번에 조회할 수 있다.
fetchType이 Lazy로 설정되어있어도 fetchJoin이 우선순위를 가지기 때문에 한번의 조회로 연관된 엔티티를 같이 조회한다.
다대일 관계에서는 fetchJoin을 쓰면 N+1 문제를 해결할 수 있다.
하지만 OneToMany 관계에서는 데이터가 카테시안 곱만큼 늘어나서 조회된다는 것이다.
그림에서 보이는 것 처럼 Yata에 YataMember가 2명 존재하는 경우 fetchJoin으로 Yata와 YataMember를 조회하는 경우 Yata가 YataMember의 수만큼 곱해져 Yata가 2개로 조회되는 문제가 발생한다.
이 문제를 해결하기 위해서는 자료의 중복을 제거하는 두가지 방법을 일반적으로 사용한다.
1.컬렉션 Set을 사용(중복허용X)
2.distinct를 사용
따라서 yata porject에서는 yataMapper 클래스에서 yataMemeber를 얻어올 때 Distinct를 사용해 중복을 제거해줌으로써, 문제를 해결하였다.
💡yataMapper 클래스
default YataDto.Response yataToYataResponse(Yata yata) {
if (yata == null) {
return null;
}
YataDto.Response.ResponseBuilder response = YataDto.Response.builder();
if (yata.getYataId() != null) {
response.yataId(yata.getYataId());
}
if (yata.getYataMembers() == null) response.reservedMemberNum(0);
else response.reservedMemberNum(yata.getYataMembers().stream().distinct().mapToInt(YataMember::getBoardingPersonCount).sum()); //중복제거
.
.
.
return response.build();
}
default List<YataDto.AcceptedResponse> yataToMyYatas(List<Yata> yatas , String email){
if (yatas == null) {
return null;
}
return yatas.stream().map(yata -> {
YataDto.AcceptedResponse response = new YataDto.AcceptedResponse();
response.setYataResponse(yataToYataResponse(yata));
response.getYataResponse().setYataMembers(null);
YataMember yataMember = yata.getYataMembers()
.stream().distinct() //중복제거
.filter(yataMember1 ->
yataMember1.getMember().getEmail().equals(email)).findFirst().orElse(null);
response.setYataMemberId(yataMember != null ? yataMember.getYataMemberId() : null);
.
.
.
return response;
}).collect(Collectors.toList());
}
'Spring' 카테고리의 다른 글
[프로젝트]토스페이 연동하기 2 (3) | 2023.06.12 |
---|---|
토스페이 API 연동 (0) | 2023.06.09 |
[프로젝트] Spring batch의 적용 (6) | 2023.06.06 |
Spring batch (0) | 2023.06.05 |
ehcache의 속성 (2) | 2023.06.02 |