스프링/5. 스프링 DB-1

40. 스프링 예외 추상화.

sdafdq 2023. 10. 5. 23:30

스프링은 저런 예외 관련한 문제에 지원을 해 주기 위해, 미리 데이터 접근과 관련된 예외를 추상화 하여 제공해 준다.

DataAccessException은 추상 클래스 이다.

저 예외들은 특정 기술에 종속적이지 않게 설계가 되어, 서비스 계층에서도 사용하면 된다.

 

또, JDBC나 JPA를 사용할 때 발생하는 예외를 스프링이 제공하는 예외로 변환해 주는 역할도 스프링이 제공해 준다.

 

스프링이 제공하는 데이터 접근 계층 예외는 크게 2가지로 구분되는데, NonTransient와 Transient다. 직역은 일시적인 이란 뜻인데, 

보면 transient 하위로 timeout등이 있는데, 말 그대로 일시적 오류라 다시 시도했을 때 성공할 가능성이 있는 것이다.

 

반대로 NonTransient는 잘못된 sql이라던지, 중복된 primary key 라던지, 다시 시도해 봤자 성공하지 않는다.

 

 

@Slf4j
public class SpringExceptionTranslatorTest {
    DataSource dataSource;

    @BeforeEach
    void init(){
        dataSource = new DriverManagerDataSource(URL,USERNAME, PASSWORD);
    }

    @Test
    void sqlExceptionErrorCode(){
        String sql = "select bad grammer";

        try{
            Connection con = dataSource.getConnection();
            PreparedStatement stmt = con.prepareStatement(sql);
            stmt.executeQuery();
        }catch (SQLException e){
            assertThat(e.getErrorCode()).isEqualTo(42122);
            int errorCode = e.getErrorCode();
            log.info("errorCode={}",errorCode);
            log.info("error",e);
        }
    }
}

먼저, 그냥 에러.

sql을 확연히 잘못 만들었다.

 

분명히 예외가 발생할 것 이고, 저것의 경우 예외코드는 42122라고 한다.

https://www.h2database.com/javadoc/org/h2/api/ErrorCode.html

 

ErrorCode

CONNECTION_BROKEN_1 public static final int CONNECTION_BROKEN_1 The error with code 90067 is thrown when the client could not connect to the database, or if the connection was lost. Possible reasons are: the database server is not running at the given por

www.h2database.com

여기서 42122 찾아봤다.

COLUM_NOT_FOUND_1

에러코드 42122는 존재하지 않은 열을 참조할 때 던져지는 코드라고 한다.

 

원래라면 우리가 예외를 활용하려면, 예외를 변환하여 MyDbBadSqlException(e) 이런 식으로 바꿔서 던졌어야 한다.

 

그리고, 아마 h2뿐만 아니라 대부분의 DB가 공식적으로 ErrorCode에 관한 정보를 제공할 것이다.

뭔가 DB관련해서 의도한 대로 동작하지 않으면서 숫자코드등을 보여주면 한번 공식문서를 참조해 보는 게 좋을 것이다.

 

 

 

다음은 스프링이 제공해주는 예외 번역기를 사용한 테스트이다.

@Test
void exceptionTranslator(){
    String sql = "select bad grammar";

    try {
        Connection con = dataSource.getConnection();
        PreparedStatement stmt = con.prepareStatement(sql);
        stmt.executeQuery();
    } catch (SQLException e){
        assertThat(e.getErrorCode()).isEqualTo(42122);
        SQLErrorCodeSQLExceptionTranslator exTranslator = new SQLErrorCodeSQLExceptionTranslator();
        DataAccessException resultEx = exTranslator.translate("translate db error to Spring Exception", sql, e);
        log.info("resultEx", resultEx);
        assertThat(resultEx.getClass()).isEqualTo(BadSqlGrammarException.class);
    }
}

SQLErrorCodeSQLExceptionTranslator 직역하면 SQL에러코드 SQL예외 번역기 이다.

사용 방법은 모든 DB접근 예외의 조상? 인 DataAccessException(추상클래스)에 exTranslater.translate(메시지, sql문, 에러)

이렇게 주면 저기에 에러가 담긴다.

말 그대로 에러를 번역해 주는 것이다. 스프링이 제공해주는 특정 기술에 종속되어 있지 않는 에러들로.(물론 스프링에 종속되어 있다고 볼 수 있지만, 그 정도는 감수한다.. 는 것 같다. 하긴 바뀔 수 있는 DB같은 거 보다는 개발환경 자체인 스프링에 종속적인건 얻는 이점에 비해 조금 아쉽지만 그리 나쁘지는 않다. 라는 느낌이다.)

 

여튼, 저 resultEx는 추상클래스를 의존하고 있지만, 결과적으로 담기는 것은 번역에 의해 구체클래스가 담긴다.

BadSqlGrammarException.