源码解析Spring 数据库异常抽理知识点总结

数据库为:H2

如果需要处理特定 SQL 异常,比如 SQL 语句错误,这个时候我们应该怎么办?

查看 SQLException 源码,我们可以发现两个重要的方法。

SQLException.getErrorCode:返回数据库特定的错误码,由数据库厂商制定,不同厂商错误码不同。如重复主键错误码在 MySQL 中是 1062,而在 Oracle 中却是 1。

SQLException.getSQLState:返回 XOPEN 或 SQL:2003 制定的错误码规范。数据库厂商会将不同错误消息映射成同一个错误码

所以我们可以根据 SQLException.getErrorCode 处理相应的数据库异常。

由于数据库厂商错误码不相同,这就导致如果我们更换数据库,上面判断逻辑就必须重写。

下面我们使用 Spring 操作数据库。

Spring 操作数据库

使用 Spring 之后,我们不再需要强制捕获异常。如果 SQL 语句运行存在异常,Spring 会抛出其内置特定的异常。如上面 SQL 语句异常将会抛出 BadSqlGrammarException。除了这个异常之外,Spring 还定义很多数据库异常。

每个 Spring 数据库异常的基类都是 DataAccessException。由于 DataAccessException 继承自 RuntimeException,所以在这类异常无需强制捕获。

在 Spring 中使用 SQLExceptionTranslator 进行异常转换,默认的转换规则会根据 SQLException.getErrorCode 返回的错误码进行相应的转换。

下面我们从源码分析转换过程。

实现细节

调试 JdbcTemplate 的源码。

可以看到这里捕获了 SQLException,转换之后再将其抛出。

整个转换过程,最后交给 SQLExceptionTranslator 进行转换。

首先我们查看 SQLExceptionTranslator 类图。

可以看到其实现了一个抽象类以及三个子类。

抽象类中会首先会使用子类转换,若未能转换成功,将会启动 fallback机制,再次转换,作为兜底。

接着我们先看下三个子类的区别。

SQLErrorCodeSQLExceptionTranslator:

默认转换类主要根据 SQLException.getErrorCode 进行转换。默认使用 SQLExceptionSubclassTranslator 作为 fallback 对象。

SQLExceptionSubclassTranslator:

基于 JDBC 的 SQLException 标准子类判断,如 java.sql.SQLTransientException。使用 SQLStateSQLExceptionTranslator 作为 fallback 对象。

SQLStateSQLExceptionTranslator:

基于 SQLException.getSQLState 规则判断。

下面分析 SQLErrorCodeSQLExceptionTranslator ,其他两个比较类似,同学们可以自己看源码分析。

SQLErrorCodeSQLExceptionTranslator 转换器主要根据 SQLException.getErrorCode 进行判断。Spring 默认在 org/springframework/jdbc/support/sql-error-codes.xml 归纳不同数据库厂商相关错误码。该配置文件会在第一次发生 SQL 异常时由 SQLErrorCodesFactory 进行加载,最后生成 SQLErrorCodes。

另外在 SQLErrorCodes 提供扩展方法,可以根据错误码转换成自定义的异常。

最后查看 SQLErrorCodeSQLExceptionTranslator 里的转换方法。

前三个方法是 Spring 留下扩展方法,可以根据自己需求分别扩展。若都没有实现,将会根据错误码判断转换成具体的异常。

自定义异常转换

上面说到 Spring 总共给我们留下三处扩展点。

继承 SQLErrorCodeSQLExceptionTranslator,重写 customTranslate。继承 SQLExceptionTranslator,重写 translate,然后在 sql-error-codes.xml注入。使用 SQLErrorCodes#customTranslations ,然后在 sql-error-codes.xml 配置相关错误码转换的规则。

第三种方式改动最小,比较简单。首先在 classpath 下生成 sql-error-codes.xml,复制原有配置,最后配置 customTranslations 。

这里需要注意的是,需要转化的异常类型必须为 DataAccessException 子类。下面面我们自定义一个异常。

总结

Spirng 异常处理将 SQL 异常转化成内置异常,屏蔽不同数据库返回码不一致的带来的问题。

最后总结本文的知识点,希望帮助到大家。

帮助

Handling SQLExceptions

郑重声明:本文版权包含图片归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们(delete@yzlfxy.com)修改或删除,多谢。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

留言与评论(共有 0 条评论)
   
验证码: