스프링은 데이터 접근과 관련된 다양한 예외를 추상화하여 제공한다.
예외의 최고 상위는 org.springframework.dao.DataAccessException 이고 그 밑은 NonTransient예외와 Transient예외로 나뉜다.
- NonTransient 예외 = 일시적이지 않은 오류(SQL 문법 오류, 데이터 베이스 제약조건 위배 ...)
- 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 |