[코드 리뷰] - Step 2.

김영훈·2024년 3월 6일
post-thumbnail

피드백 1.

    @Query("SELECT latestcommute FROM Commute latestcommute 
    WHERE latestcommute.member.id = :memberId AND latestcommute.createdAt = 
    (SELECT MAX(commute.createdAt) FROM Commute commute 
    WHERE commute.member.id = :memberId)")

📌 서브 쿼리를 이용해 가장 최근 기록을 가져오셨군요! 생각하지 못한 방법 또 하나 배우고 갑니다! 😊
추가로 질문을 드리자면 저 같은 경우는 서브쿼리는 성능이 걱정되어 불가피한 상황이 아닌 경우에는 지양하는 편인데 영훈님은 어떻게 생각하시는지 궁금합니다...!


해결 과정 1.

1. JPQL을 활용해 Join ORDER BY LIMIT 으로 변경

  • 우선 쿼리문을 수정했습니다.
@Query("SELECT latestcommute FROM Commute latestcommute 
JOIN latestcommute.member member 
WHERE member.id = :memberId 
ORDER BY latestcommute.createdAt DESC")
  • 하지만 LIMIT를 활용하려 하니, JPQL 자체적으론 LIMIT를 지원하지 않는다는 사실을 알게 되었습니다.
@Query("SELECT latestcommute FROM Commute latestcommute 
JOIN latestcommute.member member 
WHERE member.id = :memberId 
ORDER BY latestcommute.createdAt DESC")
List<Commute> findFirstByMemberId(long MemberId);
# 실제 쿼리 조회
Hibernate: 
    select
        c1_0.id,
        c1_0.attendance,
        c1_0.start_of_work,
        c1_0.member_id,
        c1_0.end_of_work 
    from
        commute c1_0 
    join
        member m1_0 
            on m1_0.id=c1_0.member_id 
    where
        m1_0.id=? 
    order by
        c1_0.start_of_work desc
  • 받아온 List를 Service 단에서 처리하려다, 모든 List를 받아오는것이 마음에 들지 않아서 JPA에 대해 조금 더 찾아보았습니다.

2. JPA 쿼리 메서드 활용

  • JPQL에서 LIMIT을 지원하지 않는데, 굳이 JPQL을 사용할 이유가 없었습니다.
Optional<Commute> findFirstByMemberIdOrderByCreatedAtDesc(Long memberId);
  • 해당 쿼리 메서드 조회시 실제 전송되는 쿼리문
Hibernate: 
    select
        c1_0.id,
        c1_0.attendance,
        c1_0.start_of_work,
        c1_0.member_id,
        c1_0.end_of_work 
    from
        commute c1_0 
    left join
        member m1_0 
            on m1_0.id=c1_0.member_id 
    where
        m1_0.id=? 
    order by
        c1_0.start_of_work desc 
    limit
        ?

💡 서브쿼리를 사용하지 않고, Left Join을 통해 최근순으로 정렬하고,
LIMIT을 통해 제일 처음(가장 최근)Commute을 반환합니다.


피드백 2.

public record startOfWorkRequest(@NotNull long id) {
    public Commute toEntity(Member member){
        return Commute.builder()
                .member(member)
                .build();
    }
}

📌 요청값 검증 처리를 위해 @NotNull 등 어노테이션을 사용하고 계신데,
요청값에 대해 예외가 발생하면 어떤식으로 응답이 나가는지 알고 계신가요?
몇몇 커스텀 예외에 대해 핸들링 해서 일관된 응답 형식으로 응답이 나가고 있는데,
요청값 검증 예외는 다른 형식으로 응답이 나갈것 같습니다.


해결 과정 2.

Edge-Case의 Exception을 우선적으로 설정하느라 @Valid 로 값 검증을 하고 있으면서도
ExceptionHandler 에서 정작 ValidException 처리하는 메서드를 만들어 놓지 않았다는걸 깨달았습니다.
따로 ValidException 처리를 하지 않았기때문에, 요청값 검증 예외가 발생한다면,
전부 500 Internal-server-error로 처리 되었을 것입니다.

@ExceptionHandler(MethodArgumentNotValidException.class)
    protected ResponseEntity<ErrorResponse> handle(MethodArgumentNotValidException e){
        e.getStackTrace();
        log.error("MethodArgumentNotValidException", e);
        return createErrorResponse(ErrorCode.INVALID_INPUT_VALUE);
    }

💡 MethodArgumentNotValidException 예외가 발생한다면,
400 Bad Request와 올바르지 않은 입력값이라는 메세지가 출력되도록 했습니다.


0개의 댓글