4.1 사라진 SQLException

4.1.1 초난감 예외처리

    1. 예외 블랙홀 - catch 문에 아무것도 넣지 않는 경우
    1. 무의미하고 무책임한 throws
  • 예외 처리시 핵심 원칙
    • 모든 예외는 적절하게 복구되거나 작업을 중단시키고 개발자에게 통보되어야 함.

4.1.2 예외의 종류와 특징

  • 체크 예외(checked exception) - 명시적인 처리가 필요한 예외를 사용하고 다루는 법
  • 자바에서 throw를 통해서 발생시킬 수 있는 예외
      1. Error - java.lang.Error 클래스의 서브클래스들
      • 시스템 레벨에서 특별한 작업을 하는게 아니라면 애플리케이션에서는 신경 쓰지 않아도 됨.
      1. Exception과 체크 예외
      • 체크 예외 - Exception 클래스의 서브클래스이면서 RuntimeException 클래스를 상속하지 않은 것.
        • 일반적으로 예외라고 하면 체크 예외라고 생각해도 됨.
        • 체크 예외가 발생할 수 있는 메소드를 사용할 경우 반드시 예외 처리 코드 작성해야함.
      • 언체크 예외(unchecked exception) - RuntimeException을 상속한 클래스들
      1. RuntimeException과 언체크/런타임 예외
      • 런타임 예외는 주로 프로그램의 오류가 있을 때 발생하도록 의도된 것임.
      • 예) NullPointerException - 오브젝트를 할당하지 않은 레퍼런스 변수 사용 시도시 발생하는 에러

4.1.3 예외처리 방법

    1. 예외 복구 - 예외상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓기
    1. 예외처리 회피 - 예외처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던지기
    • throws 문으로 선언하거나 catch 문으로 잡은 후 rethrow
    • 예외 복구처럼 회피의 의도가 분명해야함.
    1. 예외 전환 - 예외를 그대로 넘기지 않고 적절한 예외로 전화해서 던지기
    • 목적
      • 예외 던지기가 예외 상황에 대한 적절한 의미를 부여해주지 못해서 의미를 분명하게 해줄 수 있는 예외로 바꿔줌.
        • 중첩 예외로 만드는 것이 좋음.
      • 예외를 처리하기 쉽게 포장
        • 주로 예외 처리를 강제하는 체크 예외를 언체크 예외인 런타임 예외로 바꾸는 경우에 사용
  • 복구 불가능한 예외라면 애플리케이션 코드에서는 런타임 예외로 포장해서 던지는 것이 나음.

4.1.4 예외처리 전략

    1. 런타임 예외의 보편화 - 항상 복구할 수 있는 예외가 아니라면 일단 언체크 예외로 만드는 경향이 있음.
    • 낙관적인 예외처리 기법임. 복구할 수 있는 예외는 없음. 예외 발생해도 런타임 예외이므로 시스템 레벨에서 알아서 처리해줄 것이고, 꼭 필요한 경우는 런타임 예외라도 잡아서 복구하거나 대응해줄 수 있으니 문제될 것 없음.
    1. 애플리케이션 예외
    • 시스템 또는 외부의 예외상황이 원인이 아니라 애플리케이션 자체의 로직에 의해 의도적으로 발생시키고, 반드시 catch해서 무엇인가 조취를 취하도록 요구함.
    • 예) 사용자가 요청한 금액을 은행계좌에서 출금하는 기능을 가진 메소드를 설계하는 법
      • 첫번째 방법) 정상적인 출금처리 했을 경우, 잔고 부족이 발생했을 경우에 각각 다른 종류의 리턴 값 돌려줌.
      • 두번째 방법) 정상적인 흐름 코드는 그대로 두고, 잔고 부족과 같은 예외 상황에서는 비즈니스적인 의미를 띤 예외 던지기

4.1.5 SQLException은 어떻게 됐나?

  • JdbcTemplate과 콜백안에서 발생하는 모든 SQLException을 런타임 예외인 DataAccessException으로 포장해서 던져줌.
  • 스프링의 API 메소드에 정의되어 있는 대부분의 예외는 런타임 예외임. 따라서 발생 가능한 예외가 있더라도 처리하도록 강제하지 않음.

4.2 예외 전환

  • JdbcTemplate이 던지는 DataAccessException은 일단 런타임 예외로 SQLException을 포장해주는 역할을 함. → 복구 불가능한 예외인 SQLException에 대해 애플리케이션 레벨에서 신경쓰지 않도록 해줌.

4.2.1 JDBC의 한계

    1. 비표준 SQL - 대부분의 DB는 표준을 따르지 않는 비표준 문법과 기능도 제공함.
    • DAO를 DB별로 만들어 사용하거나 SQL을 독립시켜서 바꿔 쓸 수 있게하는 식으로 해결 가능
    1. 호환성 없는 SQLException의 DB 에러 정보
    • DB마다 에러의 종류와 원인이 제각각임.

4.2.2 DB 에러 코드 매핑을 통한 전환

  • 스프링은 DB별 에러 코드를 분류해서 스프링이 정의한 예외 클래스와 매핑해놓은 에러 코드 매핑정보 테이블을 만들어두고 이용함.

4.2.3 DAO 인터페이스와 DataAccessException 계층구조

  • DataAccessException은 데이터 엑세스 기술에서 발생하는 예외에도 적용됨.
  • DAO의 사용 기술과 구현 코드는 전략 패턴과 DI를 통해 DAO를 사용하는 클라이언트에게 감출 수 있지만, 메소드 선언에 나타나는 예외정보가 문제가 될 수 있음.
  • 데이터 액세스 기술이 달라지면 같은 상황에서도 다른 종류의 예외가 던져짐. → DAO의 사용기술에 따라 예외 처리 방법 달라짐.
  • 데이터 액세스 예외 추상화와 DataAccessException 계층구조
    • 스프링은 자바의 다양한 데이터 액세스 기술을 사용할 떄 발생하는 예외들을 추상화해서 DataAcessException 계층구조에 정리함.

4.2.4 기술에 독립적인 UserDao 만들기

  • DataAccessException 활용 시 주의사항
    • DataAccessException이 기술에 상관없이 추상화된 공통 예외로 변환해주지만 완벽하진 않음.
    • 학습 테스트를 만들어서 실제로 전환되는 예외의 종류 확인해야함.
    • 스프링에서의 방법 - DB 에러 코드 사용
      • SQLException을 코드에서 직접 전환하고 싶다면 SQLExceptionTranslator 인터페이스를 구현한 클래스 중에서 SQLErrorCodeExceptionTranslator 사용하면 됨.

참고 자료