初入學習 JDBC 操做數據庫,想必你們都寫過下面的代碼:html
數據庫爲:H2java
若是須要處理特定 SQL 異常,好比 SQL 語句錯誤,這個時候咱們應該怎麼辦?spring
查看 SQLException 源碼,咱們能夠發現兩個重要的方法。sql
SQLException.getErrorCode:返回數據庫特定的錯誤碼,由數據庫廠商制定,不一樣廠商錯誤碼不一樣。如重複主鍵錯誤碼在 MySQL 中是 1062,而在 Oracle 中倒是 1。數據庫
SQLException.getSQLState:返回 XOPEN 或 SQL:2003 制定的錯誤碼規範。數據庫廠商會將不一樣錯誤消息映射成同一個錯誤碼markdown
因此咱們能夠根據 SQLException.getErrorCode 處理相應的數據庫異常。oracle
因爲數據庫廠商錯誤碼不相同,這就致使若是咱們更換數據庫,上面判斷邏輯就必須重寫。oop
下面咱們使用 Spring 操做數據庫。源碼分析
使用 Spring 以後,咱們再也不須要強制捕獲異常。若是 SQL 語句運行存在異常,Spring 會拋出其內置特定的異常。如上面 SQL 語句異常將會拋出 BadSqlGrammarException。除了這個異常以外,Spring 還定義不少數據庫異常。學習
每一個 Spring 數據庫異常的基類都是 DataAccessException。因爲 DataAccessException 繼承自 RuntimeException,因此在這類異常無需強制捕獲。
在 Spring 中使用 SQLExceptionTranslator 進行異常轉換,默認的轉換規則會根據 SQLException.getErrorCode 返回的錯誤碼進行相應的轉換。
下面咱們從源碼分析轉換過程。
調試 JdbcTemplate 的源碼。
能夠看到這裏捕獲了 SQLException,轉換以後再將其拋出。
整個轉換過程,最後交給 SQLExceptionTranslator 進行轉換。
首先咱們查看 SQLExceptionTranslator 類圖。
能夠看到其實現了一個抽象類以及三個子類。
抽象類中會首先會使用子類轉換,若未能轉換成功,將會啓動 fallback機制,再次轉換,做爲兜底。
接着咱們先看下三個子類的區別。
SQLErrorCodeSQLExceptionTranslator:
SQLExceptionSubclassTranslator:
SQLStateSQLExceptionTranslator:
下面分析 SQLErrorCodeSQLExceptionTranslator ,其餘兩個比較相似,同窗們能夠本身看源碼分析。
SQLErrorCodeSQLExceptionTranslator 轉換器主要根據 SQLException.getErrorCode 進行判斷。Spring 默認在 org/springframework/jdbc/support/sql-error-codes.xml 概括不一樣數據庫廠商相關錯誤碼。該配置文件會在第一次發生 SQL 異常時由 SQLErrorCodesFactory 進行加載,最後生成 SQLErrorCodes。
另外在 SQLErrorCodes 提供擴展方法,能夠根據錯誤碼轉換成自定義的異常。
最後查看 SQLErrorCodeSQLExceptionTranslator 裏的轉換方法。
前三個方法是 Spring 留下擴展方法,能夠根據本身需求分別擴展。若都沒有實現,將會根據錯誤碼判斷轉換成具體的異常。
上面說到 Spring 總共給咱們留下三處擴展點。
第三種方式改動最小,比較簡單。首先在 classpath 下生成 sql-error-codes.xml,複製原有配置,最後配置 customTranslations 。
這裏須要注意的是,須要轉化的異常類型必須爲 DataAccessException 子類。下面面咱們自定義一個異常。
Spirng 異常處理將 SQL 異常轉化成內置異常,屏蔽不一樣數據庫返回碼不一致的帶來的問題。
最後總結本文的知識點,但願幫助到你們。