从源码解析 Spring JDBC 异常抽象
初入学习 JDBC 操作数据库,想必大家都写过下面的代码:
数据库为: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 异常转化成内置异常,屏蔽不同数据库返回码不一致的带来的问题。
最后总结本文的知识点,希望帮助到大家。

帮助
从源码解析 Spring JDBC 异常抽象的更多相关文章
- Spring5源码解析-Spring框架中的单例和原型bean
Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...
- Mybatis源码解析1—— JDBC
在之前的文章中,我为大家介绍了 Mybatis 的详细用法,算是基础教程. 详细链接:Mybatis 基础教程 言归正传,只懂基础可不行,接下来将给大家带来高阶的源码解析教程,从浅入深,通过源码解析, ...
- SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的
系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...
- 源码解析Spring AOP的加载与生效
本次博主主要进行Spring AOP这里的解析,因为在工作中使用后,却不知道背后的实现原理并在使用的过程中发现了一些认知缺陷,所以决定写这么一篇文章以供大家参考参考,进入正题. 本次博主使用了@Asp ...
- spring源码解析——spring源码导入eclipse
一.前言 众所周知,spring的强大之处.几乎所有的企业级开发中,都使用了spring了.在日常的开发中,我们是否只知道spring的配置,以及简单的使用场景.对其实现的代码没有进行深入的了 ...
- Spring源码解析--Spring的整体架构
概述 Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用.Spring是于2003 年兴起的一个轻量级的Java 开发框 ...
- 深入源码解析spring aop实现的三个过程
Spring AOP的面向切面编程,是面向对象编程的一种补充,用于处理系统中分布的各个模块的横切关注点,比如说事务管理.日志.缓存等.它是使用动态代理实现的,在内存中临时为方法生成一个AOP对象,这个 ...
- 【Mybatis源码解析】- JDBC连接数据库的原理和操作
JDBC连接数据库的原理和操作 JDBC即Java DataBase Connectivity,java数据库连接:JDBC 提供的API可以让JAVA通过API方式访问关系型数据库,执行SQL语句, ...
- Spring源码解析系列汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...
随机推荐
- 分享一个编程学习网站:https://github.com/justjavac/free-programming-books-zh_CN
分享一个编程学习网站:https://github.com/justjavac/free-programming-books-zh_CN
- AreYouBusy HDU - 3535 (dp)
AreYouBusy Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- Letters CodeForces - 978C (二分)
Time limit4000 ms Memory limit262144 kB There are nn dormitories in Berland State University, they a ...
- Linux学习-使用传统程序语言进行编译的简单范例
单一程序:印出 HelloWorld 编辑程序代码,亦即原始码 [root@study ~]# vim hello.c <==用 C 语言写的程序扩展名建议用 .c #include <s ...
- poj2195 bfs+最小权匹配
题意:给个矩阵,矩阵里有一些人和房子(人数和房子数相等),一个人只进一个房子(可以路过房子而不进),每走一步花费1美金,求所有人都进入房子的最小花费,这是典型的二分图带权匹配问题. 这题就是建图有点麻 ...
- LibreOJ2095 - 「CQOI2015」选数
Portal Description 给出\(n,k,L,R(\leq10^9)\),求从\([L,R]\)中选出\(n\)个可相同有顺序的数使得其gcd为\(k\)的方案数. Solution 记\ ...
- log4j配置输出到数据库+自定义字段
Log4j.properties配置 log4j.rootLogger = info,stdout,D,E,A3 log4j.appender.Threshold=info ### 控制台输出### ...
- Java面试题之谈谈reactor模型
reactor是什么? 事件驱动 可以处理一个或多个输入源 通过Service Handle同步的将输入事件采用多路复用分发给相应的Request Handler(一个或多个)处理 具体可参考:htt ...
- <深入理解计算机系统> CSAPP Tiny web 服务器
本文是我学习<深入理解计算机系统>中网络编程部分的学习笔记. 1. Web基础 web客户端和服务器之间的交互使用的是一个基于文本的应用级协议HTTP(超文本传输协议).一个w ...
- spring mvc处理静态文件
现在流行REST开发风格,REST风格的URL 是不希望看到例如:*.do后缀的. <servlet-mapping> <servlet-name>cxy</servle ...