功能推荐等级:* * * * *
基本思想:
Wrap各类exception或各个不同供应商专有的exception到统一的Spring exception体系上来,使得DAO可以自适应不同的实现方案,这样在具体构建DAO和实现DAO时而不用花精力去专门的处理供应商特定的exception,这些对DAO来说是原本应该是透明的。Spring提供了SQLExceptionTranslator interface,如下:
public interface SQLExceptionTranslator {
DataAccessException translate(String task, String sql, SQLException sqlEx);
}
具体做法:
DAO方法显式抛出的exception要是DataAccessException 的派生类。如:
interface / abstract class MyDAO{
abstract void delete(Long id) throws MyDataAccessException;
}
具体实现时,处理如下:
步骤一 实现DAO。最好借助Spring的 相关template:
void delete(Long id) throws MyDataAccessException{
try {
// ...
} catch (SqlException ex) {
throw getExceptionTranslator().translate("my task", sql, ex);
}catch(Other Checked Exception ex){
throw convertAllOtherCheckedExceptionToSpringExceptionHierarchy(ex);
}
步骤二:
实现SQLExceptionTranslator以及针对特定异常的专门的Exception translator。Spring已经提供了支持特定供应商的SQLExceptionTranslator实现类SQLErrorCodeSQLExceptionTranslator,而且这个实现类还内置fallback功能,可以fallback到通用的SQLStateSQLExceptionTranslator 类。可以直接使用这个SQLErrorCodeSQLExceptionTranslator类。如果哟更加个性化的需求,可以重载SQLErrorCodeSQLExceptionTranslator的方法protected DataAccessException customTranslate(String task, String sql, SQLException sqlEx) 。
在使用SQLErrorCodeSQLExceptionTranslator时,除非是直接提供了SqlErrorCodes,否则使用的其内部获取SqlErrorCodes的机制,这个机制就是使用SQLErrorCodesFactory。为了SQLErrorCodesFactory工作正常,需要设置database product name或者 datasource 对象两者之一。
步骤三:构建个性化的sql error codes,命名为sql-error-codes.xml,并且放在class path下,如下:
<bean id="DB2"
class="org.springframework.jdbc.support.SQLErrorCodes">
<property name="databaseProductName">
<value>DB2*</value>
</property>
<property name="badSqlGrammarCodes">
<value>-204,-206,-301,-408</value>
</property>
<property name="dataIntegrityViolationCodes">
<value>-803,-407</value>
</property>
<property name="invalidResultSetAccessCodes">
<list>
<value>某些值</value>
</list>
</property>
<property name="dataAccessResourceFailureCodes">
<list>
<value>某些值</value>
</list>
</property>
...
</bean>
配置完毕。
附:Spring异常代码分类约定标准:
DataAccessResourceFailureException | Data access exception thrown when a resource fails completely: for example, if we can't connect to a database using JDBC. |
InvalidResultSetAccessException | Exception thrown when a ResultSet has been accessed in an invalid fashion. Such exceptions always have a <code>java.sql.SQLException</code> root cause.
<p>This typically happens when an invalid ResultSet column index or name has been specified. Also thrown by disconnected SqlRowSets. |
BadSqlGrammarException | Exception thrown when SQL specified is invalid. Such exceptions always have a <code>java.sql.SQLException</code> root cause.
<p>It would be possible to have subclasses for no such table, no such column etc. A custom SQLExceptionTranslator could create such more specific exceptions, without affecting code using this class. |
DataIntegrityViolationException | Exception thrown when an attempt to insert or update data results in violation of an integrity constraint. Note that this is not purely a relational concept; unique primary keys are required by most database types. |
CannotAcquireLockException | Exception thrown on failure to aquire a lock during an update, for example during a "select for update" statement. |
DeadlockLoserDataAccessException | Generic exception thrown when the current process was a deadlock loser, and its transaction rolled back. |
CannotSerializeTransactionException | Exception thrown on failure to complete a transaction in serialized mode due to update conflicts. |
reserved | reserved |