Spring 抽象了一套和底层持久化技术无关的 、 面向 DAO 层的异常体系。在内部:通过异常转换器(SQLExceptionTranslator
)将不同持久化技术的异常(SQLException
,SQLException
与具体数据库强相关)转换成 Spring 的持久层异常(DataAccessException
),实现统一管理。
DataAccessException
Spring-Dao层 Root根异常,由标准的 SQLException
转化而来。
那么SQLException
如何转化为DataAccessException
的呢?
答:在 org.springframework.jdbc.support
包中定义了 SQLExceptionTranslator
接口。
DataAccessException translate(String task, @Nullable String sql, SQLException ex);
入参是标准的SQLException
,返回的是转换后的DataAccessException
。
该接口的两个实现类 SQLErrorCodeSQLExceptionTranslator
和 SQLStateSQLExceptionTranslator
。
SQLErrorCodeSQLExceptionTranslator
是根据SQLException
的错误码SQLState
进行转化,其中SQL错误码和具体异常映射关系是在:sql-error-codes.xml中声明的。如下格式
<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>
<bean id="Oracle" class="org.springframework.jdbc.support.SQLErrorCodes">
<property name="badSqlGrammarCodes">
<value>900,903,904,917,936,942,17006,6550</value>
</property>
<property name="invalidResultSetAccessCodes">
<value>17003</value>
</property>
<property name="duplicateKeyCodes">
<value>1</value>
</property>
<property name="dataIntegrityViolationCodes">
<value>1400,1722,2291,2292</value>
</property>
<property name="dataAccessResourceFailureCodes">
<value>17002,17447</value>
</property>
<property name="cannotAcquireLockCodes">
<value>54,30006</value>
</property>
<property name="cannotSerializeTransactionCodes">
<value>8177</value>
</property>
<property name="deadlockLoserCodes">
<value>60</value>
</property>
</bean>
而SQLStateSQLExceptionTranslator
是根据SQLException
中的状态码(SQLState
的前两位)进行转化的。
TransientDataAccessException
TransientDataAccessException
,瞬态异常,失败的操作重试可能会成功。
比如:QueryTimeoutException、CannotAcquireLockException异常都属于瞬态异常。
异常 | 描述 |
---|---|
QueryTimeoutException | 查询超时(Exception to be thrown on a query timeout. ) |
ConcurrencyFailureException | 并发相关的异常(Exception thrown on concurrency failure.) |
PessimisticLockingFailureException | 悲观锁,锁定引发的异常(Exception thrown on a pessimistic locking violation.) |
OptimisticLockingFailureException | 乐观锁,锁定引发的异常(Exception thrown on an optimistic locking violation.) |
CannotAcquireLockException | 获取锁失败(Exception thrown on failure to acquire a lock during an update,for example during a “select for update” statement.) |
CannotSerializeTransactionException | 在串行(serialized)的事务隔离级别中,由于update竞争失败抛出来的异常(Exception thrown on failure to complete a transaction in serializedmode due to update conflicts) |
DeadlockLoserDataAccessException | 死锁 |
TransientDataAccessResourceException | 资源暂时出现故障时导致的数据访问异常,可以进行重试(Data access exception thrown when a resource fails temporarily and the operation can be retried.) |
NonTransientDataAccessException
NonTransientDataAccessException
,非瞬态异常,重试仍然会失败。比如:BadSqlGrammarException就是该异常的子类。