BackEnd/Database

스프링 예외 추상화

연향동큰손 2025. 2. 4. 10:21

스프링은  데이터 접근과 관련된 다양한 예외를 추상화하여 제공한다.

 

 

예외의 최고 상위는 org.springframework.dao.DataAccessException 이고 그 밑은 NonTransient예외와 Transient예외로 나뉜다.

 

  1. NonTransient 예외 = 일시적이지 않은 오류(SQL 문법 오류, 데이터 베이스 제약조건 위배 ...)
  2. Transient 예외 =  SQL을 다시 시도했을때 성공할 가능성이 있는 예외

 

스프링 예외 변환기

 

스프링은 데이터베이스에서 발생하는 오류 코드를 스프링이 정의한 예외로 자동으로 변환해주는 변환기를 제공한다.

 

package hello.jdbc.exception.translator;

import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import static hello.jdbc.connection.ConnectionConst.*;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

@Slf4j 
public class SpringExceptionTranslatorTest {

    DataSource dataSource;

    @BeforeEach // 각 테스트 실행 전에 실행되는 메서드
    void init() {
        // 데이터베이스 연결을 위한 DataSource 설정
        dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
    }

    @Test
    void sqlExceptionErrorCode() {
        // 잘못된 SQL 문 실행하여 예외 발생 테스트
        String sql = "select bad grammar";
        try {
            Connection con = dataSource.getConnection(); // 데이터베이스 연결
            PreparedStatement stmt = con.prepareStatement(sql); // SQL 문 준비
            stmt.executeQuery(); // 실행 (잘못된 SQL로 인해 예외 발생 예상)
        } catch (SQLException e) {
            // SQL 오류 코드 검증 (H2 데이터베이스의 문법 오류 코드 42122 예상)
            assertThat(e.getErrorCode()).isEqualTo(42122);
            int errorCode = e.getErrorCode();
            log.info("errorCode={}", errorCode);
            // 발생한 예외를 로깅 (H2의 문법 오류 예외)
            log.info("error", e);
        }
    }

    @Test
    void exceptionTranslator() {
        // Spring의 예외 변환기를 이용하여 SQL 예외를 변환하는 테스트
        String sql = "select bad grammar";
        try {
            Connection con = dataSource.getConnection(); // 데이터베이스 연결
            PreparedStatement stmt = con.prepareStatement(sql); // SQL 문 준비
            stmt.executeQuery(); // 실행 (잘못된 SQL로 인해 예외 발생 예상)
        } catch (SQLException e) {
            // SQL 오류 코드 검증
            Assertions.assertThat(e.getErrorCode()).isEqualTo(42122);

            // Spring이 제공하는 SQL 예외 변환기 생성
            SQLErrorCodeSQLExceptionTranslator exTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);

            // SQLException을 Spring의 DataAccessException으로 변환
            DataAccessException resultEx = exTranslator.translate("select", sql, e);
            
            // 변환된 예외를 로깅
            log.info("resultEx", resultEx);

            // 변환된 예외가 BadSqlGrammarException인지 검증
            Assertions.assertThat(resultEx.getClass()).isEqualTo(BadSqlGrammarException.class);
        }
    }
}

 

exceptionTranslator 테스트에서 sql이 잘못된 문법으로 작성되었다.

 

스프링은 이러한 상황에 적절한 예외로 변환해준다.

 

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

위 코드를 통해 스프링은 발생한 예외가 BadSqlGrammarException으로 반환한다.

 

스프링이 예외를 적절하게 변환할 수 있는 이유는 sql-error-codes.xml에 각 DB별 예외 코드를 별도로 저장하고 있기 때문이다.

 

'BackEnd > Database' 카테고리의 다른 글

JdbcTemplate  (0) 2025.02.07
JDBC를 이용한 반복문제 해결 - JdbcTemplate  (0) 2025.02.04
TransactionTemplate  (0) 2025.02.01
DB 락  (0) 2025.01.19
커넥션 풀 / DataSource  (0) 2025.01.13