본문 바로가기

WEB/SPRING

토비의 스프링 파트 4 예외

올바른 예외처리는 단순히 화면에 오류메시지를 출력하는게 아니다.

무분별하게 무조건 예외를 throws 하는 것도 아니다.

예외를 처리할 때 지켜야 할 핵심원칙은 한가지다. 모든 예외는 적절하게 복구되든지

아니면 작업을 중단시키고 운영자 또는 개발자에게 분명하게 통보돼야 한다.

 

예외의 종류

 

 

체크 예외

Exception 클래스와 RuntimeException을 상속받지 않은 클래스들을 체크 예외라고 한다.

체크 예외는 예외처리를 강제하기 때문에 catch블록에서 예외를 처리하거나 throws를 정의해서 멧드 밖으로 던져야 한다.

 

언체크 예외

RuntimeException을 상속받은 클래스들을 언체크 예외라고한다.

예외처리를 해주어도 되고 안해줘도 된다.

 

예외처리 방법

예외 복구

예외상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 것이다.

사용자가 요청한 파일을 읽으려고 시도했는데 해당 파일이 없다거나 다른 문제가 있어서 읽히지가 않아서 IOException이 발생했다고 생각해보자. 이때는 사용자에게 상황을 알려주고 다른 파일을 이용하도록 안내해서 예외상황을 해결할 수 있다.

 

public void exceptionRecovery() {
    int maxRetry = 10;

    while (maxRetry > 0) {
        try {
						maxRetry--;
            jdbcContext.executeSql("delete from users");
            return;

        } catch (java.lang.Exception e) {
            System.out.println(e.getMessage());
            // 정해진 시간만큼 대기
        } finally {
            // 리소스 반납
        }
    }
}

 

예외처리 회피

예외처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 것이다.

JdbcTemplate에서는 SQLException을 모두 JdbcTemplate이 처리하도록 예외를

throws한다.

이렇게 역할이 분명히 나눠져있지 않을 때 예외를 계속해서 던지게 된다면 서버로 예외가 전달될것이다.

 

public void exceptionAvoidance() throws SQLException {
    jdbcContext.executeSql("delete from users");
}

 

예외 전환

예외를 던지는 것이지만 발생한 예외를 그대로 넘기는 게 아니라 적절한 예외로 전환해서

던지는 것이다.

예를 들어 회원가입을 처리하는 쿼리를 데이터베이스에 날렸을 때 ID가 중복되면 SQLException이 발생한다. 이 때 중복되는 ID라는 정보를 예외로 전달하기 위해서

DuplicateUserIdExcxception예외를 던지게 되면 구체적인 정보를 전달할 수 있다.

 

public void exceptionChange() throws DuplicateUserIdException, SQLException {
    try
    {
        jdbcContext.executeSql("delete from users");
    }
    catch(SQLException e)
    {
        // if id중복 에러코드이면 구체적인 예외로 전환
            throw new DuplicateUserIdException(e);

    }
}

 

DAO 인터페이스와 구현의 분리

DAO를 굳이 따로 만들어서 사용하는 이유는 무엇일까?

데이터 액세스 로직을 담은 코드를 성격이 다른 코드에서 분리하기 위해서다.

 

 

데이터 액세스 예외 추상화와 DataAccessException 계층구조

스프링은 자바의 다양한 데이터 액세스 기술을 사용할 때 발생하는 예외들을 추상화해서

DataAccessException 계층구조 안에 정리해놓았다.

 

 

 

 

 

구체적인 예외를 던지자

JdbcTemplate을 사용할 때 예외가 터지면 SQLException이 터진다.

스프링 프레임워크의 DataAccessException클래스를 이용하면 다른 데이터베이스

접근방식을 사용하여도 동일한 에러를 나타낼 수 있고 구체적인 예외처리를 도와준다.

 

@Test
public void duplicateKey() {
    userDao.deleteAll();

    User user1 = new User("gyumee", "박성철", "springno1");

    // 1 try catch 사용
    try {
        userDao.add(user1);
        userDao.add(user1);
    } catch (DuplicateKeyException e) {
        System.out.println("duplicateKey예외");
    }

    // 2 JUPITER 이용
    Assertions.assertThrows(DuplicateKeyException.class, () -> {
        userDao.add(user1);
        userDao.add(user1);

            }
    );
}

 

 

위 코드는 동일한 ID를 데이터베이스에 저장하려고 할 때 키중복이라는 구체적인 예외를

알 수 있게 되어 처리할 때 도움을 줄 수 있다.

 

 

 

DataSource를 사용해 SQLException에서 직접 DuplicateKeyException으로 전환해보자

 

 @Test
    public void sqlExceptionTranslate(){
        userDao.deleteAll();

        User user1 = new User("gyumee", "박성철", "springno1");

        try{
            userDao.add(user1);
            userDao.add(user1);
        }catch(DuplicateKeyException ex){
            SQLException sqlEx = (SQLException) ex.getRootCause();
            SQLExceptionTranslator set =
                    new SQLErrorCodeSQLExceptionTranslator((javax.sql.DataSource) this.dataSource);

            assertThat(set.translate(
                    null, null, sqlEx)).isEqualTo(DuplicateKeyException.class);

        }
    }