从源码解析 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

相关文章
相关标签/搜索