Exception

이재용·2025년 1월 1일
0

예외는 폭탄 돌리기와 같다. 잡아서 처리하거나, 처리할 수 없으면 밖으로 던져야한다.
기본적으로 언체크(런타임) 예외를 사용하자.

  • 체크 예외(Exception)

    컴파일러가 체크한다. - SQLException, IOException
    Exception 을 상속받으면 체크 예외가 된다.
    예외를 잡아서 처리하지 않으면 항상 throws에 던지는 예외를 선언해야 한다.

  • 언체크 예외, 런타임 예외(RuntimeException)

    컴파일러가 체크 하지 않는다. 기본적으로 언체크(런타임) 예외를 사용하자.
    RuntimeException을 상속받으면 언체크 예외가 된다.
    예외를 잡아서 처리하지 않아도 throws를 생략할 수 있다.

체크 예외를 처리할 수 없을 때는 throws를 사용해서 밖으로 던질 예외를 필수로 지정해 주어야 한다.

public void callThrow() throws MyCheckedException {}

체크 예외를 잡아서 처리하려면 catch(..) 를 사용해서 예외를 잡으면 된다.

public void callCatch() {
	try {
	
	} catch (Exception e) {
	
	}
}

체크 예외의 문제점

  1. 의존 관계에 대한 문제
    서비스, 컨트롤러에서 SQLException에 의존하게 된다.
    JDBC를 JPA 같은 기술로 변경하면 예외도 함께 변경해야한다. SQLException에 의존하던 모든 서비스, 컨트롤러의 코드를 JPAException에 의존하도록 고쳐야 한다.
  2. 복구 불가능한 예외
    대부분의 예외는 복구가 불가능하다. 대부분의 서비스나 컨트롤러는 문제를 해결할 수는 없다.

예외 포함과 스택 트레이스
예외를 전환할 때는 꼭! 기존 예외를 포함해야 한다. 그렇지 않으면 스택 트레이스를 확인할 때 심각한 문제가 발생한다.

public void call() {
	try {
		runSQL();
	} catch (SQLException e) {
		throw new RuntimeSQLException(e); <-기존 예외(e) 포함, e가 빠지면 기존예외 제외된 것임
	}
}

스택트레이스
catch (Exception e){
	log.info("ex", e);
}

인터페이스&서비스 계층 순수성 유지

체크 예외를 런타임 예외로 변환

public class MemberRepositoryV4_1 implements MemberRepository {
	public void update(String memberId, int money) {
		try {
			~~~~
		} catch(SQLException e) {
			throw new MyDbException(e); <-여기가 핵심
		}
	}
}

데이터 접근 예외 직접 만들기
SQLException에는 데이터베이스가 제공하는 errorCode가 들어있다. errorCode를 활용하면 데이터베이스에서 어떤 문제가 발생했는지 확인 할 수 있다.
SQL ErrorCode는 각각의 데이터베이스 마다 다르다.

스프링 예외 추상화

스프링은 데이터 접근 계층에 대한 일관된 예외 추상화를 제공한다.
스프링이 제공하는 데이터 접근 계층의 모든 예외는 런타임 예외이다.
서비스, 컨트롤러 계층에서 예외 처리가 필요하면 특정 기술에 종속적인 SQLException 같은 예외를 직접 사용하는 것이 아니라, 스프링이 제공하는 데이터 접근 예외를 사용하면 된다.

스프링이 제공하는 SQL 예외 변환기

SQLExceptionTranslator exTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource); 
DataAccessException resultEx = exTranslator.translate("select", sql, e);

스프링 예외 변환기 사용 예시
} catch (SQLException e) { 
	throw exTranslator.translate("save", sql, e); 
}

translate() 메서드의 첫번째 파라미터는 읽을 수 있는 설명이고, 두번째는 실행한 sql, 마지막은 발생된 SQLException을 전달하면 된다.

0개의 댓글