Spring 提供了一套和實現技術無關的 、 面向 DAO 層語義級別的異常體系,內部經過轉換器將不一樣持久化技術的異常轉換成 Spring 的異常,實現統一管理。spring
不少正統的 AP中,使用了過多的檢查型異常,以至於在使用 API 時,代碼中充斥了大量 try/catch 樣板式的代碼 。 大多數狀況下,這些 catch 代碼段除了記錄日誌外,並無作多少其它有益的工做。數據庫
好比 JDK 中的 JDBC API,你們都說很差用,由於檢查型異常氾濫,許多異常處理代碼喧賓奪主地侵入到業務代碼中,從而破壞了總體代碼的整潔與優雅 。設計模式
Spring 在 org.springframework.dao
中提供了一套優雅的 DAO 異常體系, 這些異常都繼承自 DataAccessException
, DataAccessException
繼承自NestedRuntimeException
, NestedRuntimeException
異常以嵌套的方式封裝了源異常 。 所以,雖然不一樣的持久化技術的特定異常被轉換到 Spring 的 DAO 異常體系中,但咱們能夠經過 getCause()
方法獲取原始異常信息 。併發
這套異常體系從 DAO 的抽象層次上定義了異常目錄樹,它使得開發者能夠很容易地關注某個特定的語義異常。而 JDBC 的 SQLException 過於底層,並且與具體數據庫強相關(好比 getErrorCode()
),不只很差編碼,並且很難移植。工具
Spring 創建了異常分類目錄,以適當的顆粒度劃分了異常類型。這樣作的好處是:編碼
DataAccessException 下有這些異常子類:hibernate
異常子類 | 說明 |
---|---|
CleanupFailureDataAccessException | 執行 DAO 操做成功,但在釋放數據資源時發生異常,如關閉 Connection 時發生異常。 |
ConcurrencyFailureException | 併發地操做數據時發生異常,如沒法獲取樂觀鎖或悲觀鎖時、死鎖引起的失敗等場景。 |
DataAccessResourceFailureException | 訪問數據資源失敗,如沒法獲取數據鏈接,沒法獲取 Hibernate 的會話等場景。 |
DataRetrievalFailureException | 獲取數據失敗,如找不到對應主鍵的數據或使用了錯誤的列索引等場景。 |
DataSourceLookupFailureException | 沒法從 JNDI 中查找到數據源。 |
DataIntegrityViolationException | 數據操做違反了數據一致性限制時拋出,如插入重複的主鍵或引用不存在的外鍵場景。 |
InvalidDataAccessApiUsageException | 不正確地調用某一種持久化技術時拋出,如在 Spring JDBC 中查詢對象在調用前沒有事先進行編譯操做,就會拋出該異常。這種異常主要是由於不正確地使用持久化技術而產生的。 |
InvalidDataAccessResourceUsageException | 在訪問數據源時使用了不正確的方法時拋出,如寫錯 SQL 語句。 |
PermissionDeniedDataAccessException | 數據訪問權限不足時拋出。如僅擁有隻讀權限卻試圖更改數據。 |
UncategorizedDataAccessException | 其它未被分類的異常。 |
Spring 爲了進一步細化錯誤問題域, 它對上述的這些一級異常類又進行了細分。設計
這套異常體系具備高度的可擴展性,當 Spring 須要對一個新的持久化技術提供支持時,只要爲其定義一個對應的子異常便可,這種方式實現了設計模式中的「開閉原則」 。3d
開閉原則( OCP )是面向對象設計中 「 可複用設計 」 的基石,是面向對象設計中最重要的原則之一,其它不少的設計原則都是實現開閉原則的一種手段 。 對於擴展是開放的,對於修改是關閉的,這意味着模塊的行爲是能夠擴展的 。 當應用的需求改變時,咱們能夠對模塊進行擴展,使其具備知足那些改變的新行爲 。日誌
通常狀況下,JDBC API 在執行數據操做出現異常時,大都會拋出 SQLException ,SQLException 把異常的細節封裝在異常屬性中,因此若是但願瞭解異常的具體緣由,咱們必須對異常屬性進行分析。
SQLException 擁有兩個表明異常具體緣由的屬性:
屬性 | 類型 | 說明 |
---|---|---|
錯誤碼 | int | 與具體數據庫相關,調用 getErrorCode() 返回。 |
SQL 狀態碼 | String | 標準錯誤代碼,由 5 個字符組成,調用 getSQLState() 返回。 |
Spring 會根據錯誤碼和 SQL 狀態碼將 SQLExeption 轉換爲對應的 Spring DAO 異常 。 在 org.springframework.jdbc.support
包中定義了 SQLExceptionTranslator
接口,該接口的兩個實現類 SQLErrorCodeSQLExceptionTranslator
和 `SQLStateSQLExceptionTranslator
分別負責處理 SQLException 中錯誤代碼和 SQL 狀態碼的轉換工做 。
其它 ORM 持久化技術都擁有一個語義明確的異常體系,因此轉換相對簡單。
**注意:**Spring4 只支持 Hibernate3.6+。
Spring 在 org.springframe.orm
中爲所支持的 ORM 技術定義了相應的子包。對應的異常轉換器也定義在這些子包中:
ORM 持久化技術 | 異常轉換器 |
---|---|
HibernateX,X 可爲 三、4 或 5 | org.springframework.orm.hibernateX.SessionFactoryUtils |
JPA | org.springframework.orm.jpa.EntityManagerFactoryUtils |
JDO | org.springframework.orm.jdo.PersistenceManagerFactoryUtils |
這些工具類除了具備異常轉換的功能外,在進行事務管理時,還提供了從事務上下文環境中返回相同會話的功能 。
Spring 也支持 myBatis 持久化技術,由於 myBatis 拋出的異常與 JDBC 相同, 都是 SQLException 異常,因此採用了和 JDBC 相同的異常轉換器 。