從源碼解析 Spring JDBC 異常抽象

初入學習 JDBC 操做數據庫,想必你們都寫過下面的代碼:html

數據庫爲:H2java

JDBC 操做數據庫

若是須要處理特定 SQL 異常,好比 SQL 語句錯誤,這個時候咱們應該怎麼辦?spring

查看 SQLException 源碼,咱們能夠發現兩個重要的方法。sql

SQLException.getErrorCode:返回數據庫特定的錯誤碼,由數據庫廠商制定,不一樣廠商錯誤碼不一樣。如重複主鍵錯誤碼在 MySQL 中是 1062,而在 Oracle 中倒是 1。數據庫

SQLException.getSQLState:返回 XOPENSQL:2003 制定的錯誤碼規範。數據庫廠商會將不一樣錯誤消息映射成同一個錯誤碼markdown

因此咱們能夠根據 SQLException.getErrorCode 處理相應的數據庫異常。oracle

JDBC 異常處理

因爲數據庫廠商錯誤碼不相同,這就致使若是咱們更換數據庫,上面判斷邏輯就必須重寫。oop

下面咱們使用 Spring 操做數據庫。源碼分析

Spring 操做數據庫

Spring 數據庫處理

使用 Spring 以後,咱們再也不須要強制捕獲異常。若是 SQL 語句運行存在異常,Spring 會拋出其內置特定的異常。如上面 SQL 語句異常將會拋出 BadSqlGrammarException。除了這個異常以外,Spring 還定義不少數據庫異常。學習

Spring 數據庫異常

每一個 Spring 數據庫異常的基類都是 DataAccessException。因爲 DataAccessException 繼承自 RuntimeException,因此在這類異常無需強制捕獲。

在 Spring 中使用 SQLExceptionTranslator 進行異常轉換,默認的轉換規則會根據 SQLException.getErrorCode 返回的錯誤碼進行相應的轉換。

下面咱們從源碼分析轉換過程。

實現細節

調試 JdbcTemplate 的源碼。

JdbcTemplate

能夠看到這裏捕獲了 SQLException,轉換以後再將其拋出。

整個轉換過程,最後交給 SQLExceptionTranslator 進行轉換。

首先咱們查看 SQLExceptionTranslator 類圖。

類圖

能夠看到其實現了一個抽象類以及三個子類。

抽象方法

抽象類中會首先會使用子類轉換,若未能轉換成功,將會啓動 fallback機制,再次轉換,做爲兜底。

接着咱們先看下三個子類的區別。

SQLErrorCodeSQLExceptionTranslator:

  1. 默認轉換類
  2. 主要根據 SQLException.getErrorCode 進行轉換。
  3. 默認使用 SQLExceptionSubclassTranslator 做爲 fallback 對象。

SQLExceptionSubclassTranslator

  1. 基於 JDBC 的 SQLException 標準子類判斷,如 java.sql.SQLTransientException
  2. 使用 SQLStateSQLExceptionTranslator 做爲 fallback 對象。

SQLStateSQLExceptionTranslator

  1. 基於 SQLException.getSQLState 規則判斷。

下面分析 SQLErrorCodeSQLExceptionTranslator ,其餘兩個比較相似,同窗們能夠本身看源碼分析。

SQLErrorCodeSQLExceptionTranslator 轉換器主要根據 SQLException.getErrorCode 進行判斷。Spring 默認在 org/springframework/jdbc/support/sql-error-codes.xml 概括不一樣數據庫廠商相關錯誤碼。該配置文件會在第一次發生 SQL 異常時由 SQLErrorCodesFactory 進行加載,最後生成 SQLErrorCodes

SQLErrorCodes

另外在 SQLErrorCodes 提供擴展方法,能夠根據錯誤碼轉換成自定義的異常。

最後查看 SQLErrorCodeSQLExceptionTranslator 裏的轉換方法。

SQLErrorCodeSQLExceptionTranslator

前三個方法是 Spring 留下擴展方法,能夠根據本身需求分別擴展。若都沒有實現,將會根據錯誤碼判斷轉換成具體的異常。

默認轉換規則

自定義異常轉換

上面說到 Spring 總共給咱們留下三處擴展點。

  1. 繼承 SQLErrorCodeSQLExceptionTranslator,重寫 customTranslate
  2. 繼承 SQLExceptionTranslator,重寫 translate,而後在 sql-error-codes.xml注入。
  3. 使用 SQLErrorCodes#customTranslations ,而後在 sql-error-codes.xml 配置相關錯誤碼轉換的規則。

第三種方式改動最小,比較簡單。首先在 classpath 下生成 sql-error-codes.xml,複製原有配置,最後配置 customTranslations

customTranslations

這裏須要注意的是,須要轉化的異常類型必須爲 DataAccessException 子類。下面面咱們自定義一個異常。

自定義異常

總結

Spirng 異常處理將 SQL 異常轉化成內置異常,屏蔽不一樣數據庫返回碼不一致的帶來的問題。

最後總結本文的知識點,但願幫助到你們。

知識圖譜

幫助

Handling SQLExceptions

相關文章
相關標籤/搜索