JDBC API는 SQLException이라는 체크 예외를 반환한다. 따라서 다른 클래스들이 JDBC에 종속적이 되는 문제가 있다. SQLException은 에러를 구분하기 위해 에러 코드를 이용하는데, 데이터베이스마다 이 에러 코드가 다 다르다.
Spring에서는 이 문제를 해결하기 위해 예외 추상화 계층과 예외 번역기를 제공한다. 예외 번역기는 SQLException을 런타임 예외인 DataAccessException으로 바꿔준다. 덕분에 클래스는 SQLException이 아닌 추상화된 스프링 데이터 접근 예외에 의존할 수 있게 된다.
DataAccessException
flowchart BT
	re[RuntimeException]
	da[DataAccessException]
	nt[NonTransient\nDataAccessException]
	di[Data\nIntegrity\nViolation\nException]
	bs[BadSql\nGrammar\nException\n]
	dk[DuplicateKey\nException\n]
	td[Transient\nDataAccessException]
	qt[Query\nTimeout\nException\n]
	ol[Optimistic\nLocking\nFailure\nException\n]
	pl[Pessimistic\nLocking\nFailure\nException\n]
	da --> re
	nt --> da
	di --> nt
	dk --> di
	bs --> nt
	td --> da
	qt --> td
	ol --> td
	pl --> td
예외는 크게 두 종류로 NonTransientDataAccessException과 TransientDataAccessException이 있다. 전자는 다시 수행해도 성공할 가능성이 없는 예외들로, 잘못된 SQL을 썼을 때, 중복 키를 사용했을때 등의 상황에 발생한다. 후자는 일시적으로 발생할 수 있는 예외들로, 타임아웃 예외와 락 실패 예외가 해당된다.
SQLExceptionTranslator
SQLException을 DataAccessException으로 변환하려면 SQLExceptionTranlator 구현체를 사용하면 된다. 에러 코드로 예외가 구분되는 경우라면 SQLErrorCodeSQLExceptionTranlator를 사용하면 된다.
SQLExceptionTranslator.translate() 메소드는 인자로 task, sql, exception을 받아 DataAccessException으로 변환해준다.
catch (SQLException e) {
	SQLExceptionTranslator exTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
	DataAccessException ex = exTranslator.tranlsate("select", sql, e);
}
