Spring Boot로 애플리케이션 개발 중 아래와 같은 에러를 만난 적이 있으신가요?
Query did not return a unique result: 3 results were returned
이 글에서는 이 오류의 원인과 해결 방법에 대해 알아보겠습니다!
특히, 발생한 문제를 LIMIT 1
을 활용해 해결한 경험을 공유하겠습니다!
이 오류는 JPA Query가 고유한(Unique) 결과를 반환해야 하는데, 여러 개의 결과를 반환했을 때 발생합니다.
예를 들어, 아래와 같은 상황을 가정해 보겠습니다.
LIMIT 1
없이 실행되었고, 데이터베이스에는 동일 조건을 만족하는 여러 메시지가 존재했습니다.@Query("SELECT m FROM ChatMessage m WHERE m.user = :user AND m.partner = :partner ORDER BY m.timestamp DESC")
ChatMessage findTopByUsersOrderByTimestampDesc(@Param("user") User user, @Param("partner") User partner);
위와 같은 JPQL 쿼리가 실행되었을 때, 반환된 결과가 3개 이상이라면 해당 오류가 발생합니다.
LIMIT 1
적용이 문제를 해결하기 위해 JPQL 또는 Query Method를 수정하여 데이터베이스에서 첫 번째 결과만 가져오도록 설정해야 합니다.
Spring Data JPA는 이를 위해 findTopBy
또는 findFirstBy
메서드 키워드를 제공합니다. 이를 활용하면 LIMIT 1
이 자동으로 적용됩니다.
수정된 코드
@Query("SELECT m FROM ChatMessage m WHERE m.user = :user AND m.partner = :partner ORDER BY m.timestamp DESC")
List<ChatMessage> findTopByUsersOrderByTimestampDesc(@Param("user") User user, @Param("partner") User partner);
이후 결과를 가져올 때 다음과 같이 첫 번째 메시지만 반환하도록 처리합니다
List<ChatMessage> lastMessages = chatMessageRepository.findTopByUsersOrderByTimestampDesc(user, partner);
ChatMessage lastMessage = lastMessages.isEmpty() ? null : lastMessages.get(0);
여기서 findTopBy
는 결과를 정렬 후, 가장 위에 있는 결과를 가져오는 방식입니다. JPA가 자동으로 LIMIT 1
을 쿼리에 추가해줍니다.
만약 단일 결과만 반환하도록 강제하려면, 메서드의 반환 타입을 Optional<ChatMessage>
로 변경하는 것도 하나의 방법입니다.
Optional<ChatMessage> findTopByUserAndPartnerOrderByTimestampDesc(User user, User partner);
위 방식은 다음과 같은 장점이 있습니다
Optional
을 사용하면 결과가 없을 때 NullPointerException을 방지할 수 있습니다.Query did not return a unique result
오류를 근본적으로 방지할 수 있습니다.사용 예
Optional<ChatMessage> lastMessageOpt = chatMessageRepository.findTopByUserAndPartnerOrderByTimestampDesc(user, partner);
ChatMessage lastMessage = lastMessageOpt.orElse(null);
findTopBy
또는 LIMIT 1
을 사용하는 것을 권장합니다.user
, partner
, timestamp
를 기준으로 유니크 제약 조건(Unique Constraint)을 추가하는 것도 좋은 방법입니다.Optional
을 활용하고, 다중 결과를 예상한다면 리스트로 반환하도록 설정하세요.Spring Boot에서 발생한 "Query did not return a unique result" 오류는 다중 결과를 반환하는 쿼리가 단일 결과로 반환되기를 기대할 때 발생하였습니다. 이 문제를 해결하기 위해 LIMIT 1
을 적용하거나, findTopBy
메서드를 활용하여 데이터를 정확히 제한하는 방법을 사용해야 합니다.
여러분도 이와 같은 문제를 경험하셨다면, 위의 방법을 참고해보시기 바랍니다!! 궁금한 점은 댓글로 남겨주시면 답변 드리겠습니다. 😊