SQLExceptionTranslator — це інтерфейс, який має бути реалізований класами, здатними виконувати перетворення між SQLExceptions та власними org.springframework.dao.DataAccessException, які залежать від стратегії доступу до даних. Реалізації можуть бути типізованими (наприклад, використання кодів SQLState для JDBC) або пропрієтарними (наприклад, використання кодів помилок Oracle) для більшої точності.

SQLErrorCodeSQLExceptionTranslator – це реалізація SQLExceptionTranslator, яка використовується за замовчуванням. У цій реалізації використовуються певні коди виробників. Вона більш точна, ніж реалізація SQLState. Перетворення кодів помилок базується на кодах, що зберігаються в класі JavaBean під назвою SQLErrorCodes. Цей клас створюється та заповнюється SQLErrorCodesFactory, яка (як випливає з назви) є фабрикою для створення SQLErrorCodes на основі конфігураційного файлу sql-error-codes.xml. Цей файл заповнюється кодами виробників і ґрунтується на DatabaseProductName, взятому з DatabaseMetaData. Використовуються коди для фактичної бази даних, яку ти використовуєш.

SQLErrorCodeSQLExceptionTranslator застосовує правила узгодження в наступній послідовності:

  1. Будь-яке кастомне перетворення, реалізоване підкласом. Зазвичай використовується конкретний SQLErrorCodeSQLExceptionTranslator, тому це правило не застосовується. Воно застосовується лише в тому випадку, якщо ти дійсно надав реалізацію підкласу.

  2. Будь-яка кастомна реалізація інтерфейсу SQLExceptionTranslator, яка надається як властивість customSqlExceptionTranslator класу SQLErrorCodes.

  3. У списку екземплярів класу CustomSQLErrorCodesTranslation (наданих для властивості customTranslations класу SQLErrorCodes) виконується пошук збігу.

  4. Застосовується зіставлення кодів помилок.

  5. Використовується зворотний перетворювач (translator). SQLExceptionSubclassTranslator є стандартним перетворювачем. Якщо цей переклад недоступний, наступним поворотним перетворювачем є SQLStateSQLExceptionTranslator.

SQLErrorCodesFactory використовується за замовчуванням для визначення кодів Error та кастомних перетворень винятків. Вони шукаються у файлі sql-error-codes.xml з classpath, а відповідний екземпляр SQLErrorCodes знаходиться на основі імені бази даних із метаданих бази даних, що використовується.

Можна розширити SQLErrorCodeSQLExceptionTranslator, як показано в наступному прикладі:

Java
public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
    protected DataAccessException customTranslate(String task, String sql, SQLException sqlEx) {
        if (sqlEx.getErrorCode() == -12345) {
            return new DeadlockLoserDataAccessException(task, sqlEx);
        }
        return null;
    }
}
Kotlin
class CustomSQLErrorCodesTranslator : SQLErrorCodeSQLExceptionTranslator() {
    override fun customTranslate(task: String, sql: String?, sqlEx: SQLException): DataAccessException? {
        if (sqlEx.errorCode == -12345) {
            return DeadlockLoserDataAccessException(task, sqlEx)
        }
        return null
    }
}

У попередньому прикладі перетворюється конкретний код помилки (-12345), а решта помилок залишається на розсуд стандартної реалізації перетворювача. Щоб використовувати цей кастомний перетворювач, потрібно передати його JdbcTemplate через метод setExceptionTranslator, а потім використовувати цей JdbcTemplate для будь-якої обробки доступу до даних, де цей перетворювач необхідний. У цьому прикладі показано, як можна використовувати цей кастомний перетворювач:

Java
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
    // створюємо шаблон JdbcTemplate та встановлюємо джерело даних
    this.jdbcTemplate = new JdbcTemplate();
    this.jdbcTemplate.setDataSource(dataSource);
    // Створюємо кастомний перетворювач і встановлюємо джерело даних для пошуку перетворення за замовчуванням
    CustomSQLErrorCodesTranslator tr=new CustomSQLErrorCodesTranslator();
    tr.setDataSource(dataSource);
    this.jdbcTemplate.setExceptionTranslator(tr);
}
public void updateShippingCharge(long orderId, long pct) {
    // використовуємо підготовлений шаблон JdbcTemplate для цього оновлення
    this.jdbcTemplate.update("update orders" +
        "set shipping_charge = shipping_charge *? / 100" +
        " where id = ?", pct, orderId);
}
Kotlin
// створюємо шаблон JdbcTemplate і встановлюємо джерело даних
private val jdbcTemplate = JdbcTemplate(dataSource).apply {
    // Створюємо кастомний перетворювач і встановлюємо джерело даних для пошуку перетворення за замовчуванням
    exceptionTranslator = CustomSQLErrorCodesTranslator().apply {
        this.dataSource = dataSource
    }
}
fun updateShippingCharge(orderId: Long, pct: Long) {
    // використовуємо підготовлений шаблон JdbcTemplate для цього оновлення
    this.jdbcTemplate!!.update("update orders" +
            "set shipping_charge = shipping_charge *? / 100" +
            " where id = ?", pct, orderId)
}

Кастомному перетворювачу передається джерело даних для пошуку кодів помилок у sql-error-codes.xml.