작성
·
118
·
수정됨
0
리포지토리 계층에서 모든 데이터 액세스 기술에서 발생하는 예외는 DataAccessException으로 랩핑되어서 던져진다고 말씀하셨는데 받는 쪽인 서비스 계층에서는 DataAccessException의 서브클래스 타입의 예외를 받게 될거 같은데요. 서비스 계층에서 받게 되는 예외가 예를 들어 DuplicateKeyException이라서 처리를 하게 된다면 서비스 계층은 특정 리포지토리의 예외에 종속적이게 될거 같습니다. 그래서 컨트롤러 단으로 예외를 넘겨 ExceptionHandler로 처리해주는 것이 좋은 방법일까?에 대해서 질문 드리고 싶습니다.
근데 만약 서비스 계층에서 처리한다면,
// @Service 안에 있는 있는 일부 코드 (회원가입 로직)
public boolean saveCustJoinInfo(UserDto userDto) {
String pwd1 = userDto.getPwd().split(",")[0];
String password = passwordEncoder.encode(pwd1);
userDto.setPwd(password);
try {
userDao.insertUser(userDto);
return true;
} catch (DataAccessException e) {
return false;
}
}
이렇게 처리해도 문제가 없는가에 대해 궁금합니다.
예외 처리에 대한 여러 블로그들을 읽어봤는데 다수의 사람들이 사용자 정의 예외클래스를 정의해서 던지도록 한 이유도 궁금합니다.
만약 이 방법이 좋지 않다면 어떤 계층에서 처리하면 특정 계층이 기술에 종속적이지 않게 예외를 처리할 수 있는지 조언해 주시면 감사하겠습니다.
토비님의 스프링 강의를 일주일 만에 완강했는데 너무 좋은 강의라 부트 강의도 구매하였습니다ㅎㅎ
아키텍처에 대한 강의도 고려하시고 있다고 하셨는데 기다리고 있겠습니다!!
답변 2
0
DuplicateKeyException는 특정 데이터 액세스 기술이나 구현, DB에 종속되지 않도록 만들어진 비즈니스적인 의미가 담긴 예외입니다. 중복 값을 허용하지 않으므로 등록에 실패했다는 것만 담겨져있죠. 이걸 등록 처리라는 비즈니스 로직 안에서 "복구"할 수 있는 예외로 취급하고 재시도라는 로직에 사용한다면 아무 문제가 없습니다. 서비스는 리포지토리를 이용해서 데이터를 저장하거나 가져온다는 건 자신의 로직을 처리하는 기본 전제라서 문제는 없습니다.
올려주신 예제는 비밀번호를 암호화해서 이를 저장한다는 기본 로직의 구현에는 아무 문제는 없습니다.
그런데 DataAccessException을 캐치해서 이걸 boolean으로 리턴하는 건, 특별한 이유가 있는 게 아니라면 별로 좋아보이지 않네요. 재시도 등을 통해서 예외를 복구할 수 없다면 그냥 예외가 앞으로 던져지도록 아무 것도 하지 않는게 가장 좋습니다. 이걸 캐치해서 다른 시도를 하거나 특별한 처리하는 게 필요하다면 더 앞쪽에서 하는 게 맞고요, 데이터 저장에서 예외가 발생하는 경우엔 보통 특별한 대응이 없으니 어디서든 굳이 catch할 필요도 없는게 일반적이긴 합니다.
물론 이 메소드를 호출하는 쪽에서 저장 실패인 경우 꼭 boolean으로 받아야 한다고 요구를 했다면 어쩔 수 없겠지만요.
이어서 궁금한 점이 하나 있다면,
그럼 리포지토리에서 예외가 일어나면 추상화 된 DataAccessException을 던지게 될텐데
복구 가능한 것은 처리하되 복구 불가능한 것들은 일관성있게 공통으로 처리하기 위해서 ControllerAdvice를 이용해 처리하면 되는걸까요?
네. 복구 불가능한 건 API 응답에 에러로 전환할테니 DataAccessException의 종류에 따라서 적절한 HTTP 상태코드 또는 Body에 에러 코드를 넣어서 응답하도록 ControllerAdvice를 정책에 따라 구현하시면 됩니다. 사용자가 넣은 값에 의한 중복키 정도를 제외하면 대부분 서버 장애나 버그일테니 500대 에러로 처리하시면 되겠죠.
0
안녕하세요, 인프런 AI 인턴입니다.
springYam님의 질문에 대해 답변 드리겠습니다. 예외 처리 방식에 대한 고민은 매우 중요한 부분입니다. 서비스 계층에서 특정 데이터 액세스 기술에 종속적인 예외를 직접 다루게 되면, 나중에 다른 기술로 교체하거나 다른 저장소를 사용할 때 변경의 폭이 커져 유지 보수에 어려움을 겪을 수 있습니다.
리포지토리 계층에서 발생하는 예외를 DataAccessException으로 랩핑하여 던지는 것은 이런 종속성 문제를 해결할 수 있는 좋은 방법입니다. 그러나 서비스 계층에서 발생하는 모든 DataAccessException을 포착하여 처리하게 되면, 예외의 구체적인 원인을 파악하거나 적절히 대응하기 어려울 수 있습니다.
사용자 정의 예외 클래스를 정의하여 사용하는 것은 이러한 문제를 해결하는 또 다른 방법입니다. 서비스 계층에서 발생할 수 있는 다양한 예외 상황을 미리 정의해 두고, 발생 가능한 예외를 명확하게 표현함으로써 코드의 가독성을 높이고, 다른 개발자가 코드를 이해하기 쉽게 만드는 효과가 있습니다. 또한, 리포지토리나 다른 외부 서비스에서 발생하는 예외를 서비스 계층의 예외로 변환하여 상위 계층(예: 컨트롤러)에 전달함으로써 계층 간의 종속성을 줄이고, 애플리케이션의 전체적인 예외 처리 전략을 일관되게 유지할 수 있습니다.
컨트롤러 단에서 ExceptionHandler를 사용하여 예외를 처리하는 것도 좋은 방법입니다. 이를 통해 예외 처리 로직을 분리하고, 일관된 예외 응답 구조를 제공하며, API 사용자에게 보다 명확한 에러 메시지와 정보를 제공할 수 있습니다.
결론적으로, 특정 계층이 기술에 종속적이지 않게 예외를 처리할 수 있는 방법으로는,
- 데이터 액세스 예외를 추상화하여 서비스 계층에서 발생할 수 있는 예외로 변환
- 사용자 정의 예외 클래스를 사용하여 명확하고 관리 가능한 예외 계층 구조를 만듦
- 컨트롤러에서 ExceptionHandler를 사용하여 애플리케이션 전체의 예외 응답을 일관되게 관리
이상으로 예외 처리에 대한 질문에 대해 답변을 마치겠습니다. 토비의 스프링 강의 완강을 축하드리며, 앞으로도 많은 학습과 성장을 이루시길 바랍니다.
답변 감사합니다!!