从源码解析 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源 ...
随机推荐
- MYSQL安装与库的基本操作
mysql数据库 什么是数据库 # 用来存储数据的仓库 # 数据库可以在硬盘及内存中存储数据 数据库与文件存储数据区别 数据库本质也是通过文件来存储数据, 数据库的概念就是系统的管理存储数据的文件 数 ...
- python 项目中包中__init__.py文件的作用
开发python项目时,我遇到了一个这样的现象,当我新建一个pythonpackage时,总会自动地生成一个空的__init__.py文件,因为是python新手,所以很不了解这个空文件的作用是什么, ...
- CentOS 7 安装 配置 Nginx + PHP
. CentOS 7 下配置 yum 安装 Nginx. 进入/etc/yum.repos.d/目录下创建一个源配置文件nginx.repo: cd /etc/yum.repos.d/ vim ngi ...
- cf 1017C
C. The Phone Number time limit per test 1 second memory limit per test 256 megabytes input standard ...
- Leetcode 75. 颜色分类
题目链接 https://leetcode-cn.com/problems/sort-colors/description/ 题目描述 给定一个包含红色.白色和蓝色,一共 n 个元素的数组,原地对它们 ...
- Linux学习-什么是登录档
CentOS 7 登录档简易说明 登录档的重要性 为什么说登录文件很重要, 解决系统方面的错误: 用 Linux 这么久了,你应该偶而会发现系统可能会出现一些错误,包括硬件捉不到或者是某些系 统服务无 ...
- Python虚拟机之while循环控制结构(三)
Python虚拟机中的while循环控制结构 在Python虚拟机之if控制流(一)和Python虚拟机之for循环控制流(二)两个章节中,我们介绍了if和for两个控制结构在Python虚拟机中的实 ...
- HashMap的C++实现
#include <iostream> #include <cstring> #include <string> typedef unsigned int SIZE ...
- [转] 查看 SELinux状态及关闭SELinux
本文转载自: http://bguncle.blog.51cto.com/3184079/957315 查看SELinux状态: 1./usr/sbin/sestatus -v ##如果SE ...
- day01_08.三大控制结构
编程三要素:变量,运算,控制 控制: 有选择性的控制让你某部分代码执行,某部分不执行,或者来回反复执行某段代码 控制的三种基本机构:顺序,选择,循环 1.顺序 程序从上到下,顺序执行 <?php ...