프로젝트를 진행하며 queryForObject에 대해 공부한것을 정리해보려 한다.
List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
처음에 구현한 코드로, Member 테이블에서 "ID"는 unique한 컬럼이다. 따라서, 최대 단일 행이 조회되는것인데, List 객체를 반환하는것이 사실상 의미가 없다.
queryForObject 사용 이유
1.단일 행 반환이기에 List 필요없음
2.내 코드를 보는 누군가에게 단일 행을 조회하는 것을 명시
이러한 이유들로 queryForObject를 사용하는것이 좋다고 생각했다.
🚫 에러처리
그런데, 하나 더 유의할게 있었다. 최대 단일 행 반환이지, 일치하는 ID가 데이터베이스에 없다면 반환할 객체가 없다. queryForObejct는 반환할 행이 1개가 아니면 에러가 발생한다.
0개의 행이 반환되면 EmptyResultDataAccessException,
1개 초과일 경우 IncorrectResultSizeDataAccessException 예외가 발생한다.
try-catch로 해결
public Optional<Member> findByID(String id) {
try {
Member member = jdbcTemplate.queryForObject("select * from member where id = ?", memberRowMapper(), id);
return Optional.of(member);
} catch (EmptyResultDataAccessException e) {
return Optional.empty();
}
}
그렇기에 해당 코드처럼 try-catch문을 사용해 에러 처리를 해줬다.
의문점
queryForObject를 사용할때, 행이 0개 반환되는것에 관해 EmptyResultDataAccessException 에러처리를 해줬다. 이는 DB 에러인 DataAccessException 를 상속받으며 500 서버에러로 간주된다.
사실 애플리케이션에서 이러한 에러가 발생할 수 있는 상황은 애플리케이션을 사용하는 사용자가 ID를 잘못 입력한 경우이다. 그런데 그것을 서버 에러로 간주하고 코드 내에서 에러 핸들링 하는게 맞는 방향일까?
결론
해당 내용을 고민하다가 멘토님에게 질문을 드려봤다.
멘토님의 답변은 “정답은 없다!”였다. 모든것은 적절하게 유스케이스에 맞게 결정하면 된다고 하셨다. 멘토님의 답변중 정답이 없다가 결론인 경우가 많다.. 하지만 모든것은 트레이드오프를 따져가며 결정하는 것이 맞다.
따라서, 내가 내린 결론은 다음과 같다.
해당 경우는 DB 드라이버의 스펙과 데이터상으로 발생할 수 있는 케이스에 대해 명확하게 인지하고 있기 때문에, 서버 에러가 아닌 예외를 내부 애플리케이션 클라이언트 레벨의 예외로 핸들링 하는게 좋을 수도 있다. 대신, repository내부에서만 List인것을 알고있고 외부관점에서는 단일 엔티티로 반환한다라는것을 명확하게 한다.
'Programming > Spring,JPA' 카테고리의 다른 글
[JPA] JPA 상속관계 매핑(@Inhertinace) (0) | 2024.11.18 |
---|---|
[Spring] 예외 처리에만 국한되지 않는 @ControllerAdvice (0) | 2024.10.26 |
[Spring] 스프링에서 사용되는 디자인 패턴들 (0) | 2024.10.25 |
[Spring] 스프링 삼각형(IoC/DI, AOP, PSA) (1) | 2024.10.25 |
[JPA] 영속성 컨텍스트(Persistence Context) 내부 구조 살펴보기 (1) | 2024.10.25 |