Using SQLExceptionTranslator
SQLExceptionTranslator 是一个由类实现的接口,可以在 SQLExceptions 和 Spring 自己的 org.springframework.dao.DataAccessException
之间进行转换,它与数据访问策略无关。实现可以是通用的(例如,为 JDBC 使用 SQLState 代码)或专有的(例如,使用 Oracle 错误代码),以获得更高的精度。
SQLErrorCodeSQLExceptionTranslator 是 SQLExceptionTranslator 的实现,默认使用。这个实现使用特定的供应商代码。它比 SQLState 的实现更精确。错误代码的翻译是基于一个叫做 SQLErrorCodes 的 JavaBean 类型类中的代码。这个类是由 SQLErrorCodesFactory 创建和填充的,(顾名思义)它是一个基于名为 sql-error-codes.xml
的配置文件内容来创建 SQLErrorCodes 的工厂。这个文件是根据 DatabaseMetaData 中的 DatabaseProductName 来填充供应商代码的。你正在使用的实际数据库的代码被使用。
SQLErrorCodeSQLExceptionTranslator 按以下顺序应用匹配规则:
任何由子类实现的自定义翻译。通常,提供的具体的 SQLErrorCodeSQLExceptionTranslator 被使用,所以这个规则并不适用。只有当你实际提供了一个子类的实现时,它才适用。
SQLExceptionTranslator 接口的任何自定义实现,它被作为 SQLErrorCodes 类的 customSqlExceptionTranslator 属性提供。
CustomSQLErrorCodesTranslation 类的实例列表(为 SQLErrorCodes 类的 customTranslations 属性提供)被搜索匹配。
错误代码匹配被应用。
使用后备翻译器。SQLExceptionSubclassTranslator 是默认的后备翻译器。如果这个翻译不可用,下一个回退翻译器是 SQLStateSQLExceptionTranslator。
:::info SQLErrorCodesFactory 默认用于定义错误代码和自定义异常翻译。它们在 classpath 的一个名为 sql-error-codes.xml 的文件中被查找,并且根据使用中的数据库元数据中的数据库名称找到匹配的 SQLErrorCodes 实例。 :::
下面是 sql-error-codes.xml 中 mysql 错误代码的定义
<bean id="MySQL" class="org.springframework.jdbc.support.SQLErrorCodes">
<property name="databaseProductNames">
<list>
<value>MySQL</value>
<value>MariaDB</value>
</list>
</property>
<property name="badSqlGrammarCodes">
<value>1054,1064,1146</value>
</property>
<property name="duplicateKeyCodes">
<value>1062</value>
</property>
<property name="dataIntegrityViolationCodes">
<value>630,839,840,893,1169,1215,1216,1217,1364,1451,1452,1557</value>
</property>
<property name="dataAccessResourceFailureCodes">
<value>1</value>
</property>
<property name="cannotAcquireLockCodes">
<value>1205,3572</value>
</property>
<property name="deadlockLoserCodes">
<value>1213</value>
</property>
</bean>
看上去也就 6 种类型的异常。
你可以扩展 SQLErrorCodeSQLExceptionTranslator,如下例所示:
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;
}
}
在前面的例子中,特定的错误代码(-12345)被翻译了,而其他错误则由默认翻译器实现来翻译。要使用这个自定义翻译器,你必须通过setExceptionTranslator
方法将其传递给 JdbcTemplate,而且你必须在所有需要这个翻译器的数据访问处理中使用这个 JdbcTemplate。下面的例子展示了如何使用这个自定义翻译器:
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
// create a JdbcTemplate and set data source
this.jdbcTemplate = new JdbcTemplate();
this.jdbcTemplate.setDataSource(dataSource);
// 创建一个自定义的翻译器,并为默认的翻译查询设置数据源。
CustomSQLErrorCodesTranslator tr = new CustomSQLErrorCodesTranslator();
tr.setDataSource(dataSource); // 设置数据源的目的是为了识别数据库是什么类型,好从 sql-error-codes.xml 中查找错误代码。
this.jdbcTemplate.setExceptionTranslator(tr);
}
public void updateShippingCharge(long orderId, long pct) {
// use the prepared JdbcTemplate for this update
this.jdbcTemplate.update("update orders" +
" set shipping_charge = shipping_charge * ? / 100" +
" where id = ?", pct, orderId);
}
自定义翻译器被传递给一个数据源,以便在 sql-error-codes.xml 中查找错误代码。