엔티티 직접 노출
@GetMapping("/api/v1/simple-reserves")
public List<Reserve> reserve1(){
List<Reserve> all = reserveRepository.findAllByString(new ReserveSearch());
for (Reserve reserve : all) {
reserve.getMember().getName(); // Lazy 강제 초기화
}
return all;
}
- 엔티티를 직접 노출하는 것은 좋지 않음
엔티티를 DTO로 변환
@GetMapping("/api/v2/simple-reserves")
public List<SimpleReserveDto> reserveV2(){
List<Reserve> reserves = reserveRepository.findAllByString(new ReserveSearch());
List<SimpleReserveDto> result = reserves.stream()
.map(r -> new SimpleReserveDto(r))
.collect(Collectors.toList());
return result;
}
...
@Data
static class SimpleReserveDto{
private Long reserveId;
private String name;
private LocalDateTime reserveData;
private ReserveStatus reserveStatus;
private Address address;
public SimpleReserveDto(Reserve reserve) {
reserveId = reserve.getId();
name = reserve.getMember().getName();
reserveData = reserve.getReserveDate();
reserveStatus = reserve.getStatus();
address = reserve.getMember().getAddress();
}
}
- 1 + N 문제 발생
- 최악의 경우 총 1 + N번 실행
- reserve 조회 1번 + reserve -> member 지연 로딩 조회 N 번
- reserve 조회 시 2개의 예약이 조회
- 예약 1개당 reserve.getMember.getName()과 reserve.getMember.getAddress()로 인해 member 조회
- 만약 첫번째 예약에서 찾은 member와 두번째 예약에서 찾는 member가 같은 경우 N번이 아닌 1번만 실행
- 지연로딩은 영속성 컨텍스트에서 조회하믈, 이미 조회된 경우 쿼리를 생략
페치 조인 최적화
// Repository
public List<Reserve> findAllWithMember() { // 페치 조인 적용
return em.createQuery(
"select r from Reserve r" +
" join fetch r.member m", Reserve.class
).getResultList();
}
...
// Controller
@GetMapping("/api/v3/simple-reserves")
public List<SimpleReserveDto> reserveV3(){
List<Reserve> reserves = reserveRepository.findAllWithMember();
List<SimpleReserveDto> result = reserves.stream()
.map(r -> new SimpleReserveDto(r))
.collect(Collectors.toList());
return result;
}
...
@Data
static class SimpleReserveDto{
private Long reserveId;
private String name;
private LocalDateTime reserveData;
private ReserveStatus reserveStatus;
private Address address;
public SimpleReserveDto(Reserve reserve) {
reserveId = reserve.getId();
name = reserve.getMember().getName();
reserveData = reserve.getReserveDate();
reserveStatus = reserve.getStatus();
address = reserve.getMember().getAddress();
}
}
- Repository의 findAllWithMember 메소드 선언하여 페치 조인 사용
- 페치 조인으로 reserve -> member는 이미 조회 된 상태이므로 더 이상 조회 쿼리 X
'개발진행목록 > 예약 서비스' 카테고리의 다른 글
예약 리스트 조회 API 순환참조 해결 (0) | 2024.10.29 |
---|---|
회원 관련 API 개발 (0) | 2024.10.17 |
설계 (0) | 2024.09.20 |