初入学习 JDBC 操做数据库,想必你们都写过下面的代码:html
数据库为:H2java
若是须要处理特定 SQL 异常,好比 SQL 语句错误,这个时候咱们应该怎么办?spring
查看 SQLException 源码,咱们能够发现两个重要的方法。sql
SQLException.getErrorCode:返回数据库特定的错误码,由数据库厂商制定,不一样厂商错误码不一样。如重复主键错误码在 MySQL 中是 1062,而在 Oracle 中倒是 1。数据库
SQLException.getSQLState:返回 XOPEN 或 SQL:2003 制定的错误码规范。数据库厂商会将不一样错误消息映射成同一个错误码oracle
因此咱们能够根据 SQLException.getErrorCode 处理相应的数据库异常。源码分析
因为数据库厂商错误码不相同,这就致使若是咱们更换数据库,上面判断逻辑就必须重写。学习
下面咱们使用 Spring 操做数据库。spa
使用 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 异常转化成内置异常,屏蔽不一样数据库返回码不一致的带来的问题。
最后总结本文的知识点,但愿帮助到你们。