初入学习 JDBC 操作数据库,想必大家都写过下面的代码:

数据库为:H2

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

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

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

SQLException.getSQLState:返回 XOPENSQL: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:

  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 提供扩展方法,可以根据错误码转换成自定义的异常。

最后查看 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

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

总结

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

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

帮助

Handling SQLExceptions

从源码解析 Spring JDBC 异常抽象的更多相关文章

  1. Spring5源码解析-Spring框架中的单例和原型bean

    Spring5源码解析-Spring框架中的单例和原型bean 最近一直有问我单例和原型bean的一些原理性问题,这里就开一篇来说说的 通过Spring中的依赖注入极大方便了我们的开发.在xml通过& ...

  2. Mybatis源码解析1—— JDBC

    在之前的文章中,我为大家介绍了 Mybatis 的详细用法,算是基础教程. 详细链接:Mybatis 基础教程 言归正传,只懂基础可不行,接下来将给大家带来高阶的源码解析教程,从浅入深,通过源码解析, ...

  3. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  4. 源码解析Spring AOP的加载与生效

    本次博主主要进行Spring AOP这里的解析,因为在工作中使用后,却不知道背后的实现原理并在使用的过程中发现了一些认知缺陷,所以决定写这么一篇文章以供大家参考参考,进入正题. 本次博主使用了@Asp ...

  5. spring源码解析——spring源码导入eclipse

    一.前言     众所周知,spring的强大之处.几乎所有的企业级开发中,都使用了spring了.在日常的开发中,我们是否只知道spring的配置,以及简单的使用场景.对其实现的代码没有进行深入的了 ...

  6. Spring源码解析--Spring的整体架构

    概述 Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用.Spring是于2003 年兴起的一个轻量级的Java 开发框 ...

  7. 深入源码解析spring aop实现的三个过程

    Spring AOP的面向切面编程,是面向对象编程的一种补充,用于处理系统中分布的各个模块的横切关注点,比如说事务管理.日志.缓存等.它是使用动态代理实现的,在内存中临时为方法生成一个AOP对象,这个 ...

  8. 【Mybatis源码解析】- JDBC连接数据库的原理和操作

    JDBC连接数据库的原理和操作 JDBC即Java DataBase Connectivity,java数据库连接:JDBC 提供的API可以让JAVA通过API方式访问关系型数据库,执行SQL语句, ...

  9. Spring源码解析系列汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...

随机推荐

  1. Memcached配置失误引发的Keystone token丢失的问题

    故障现象 近期公司的OpenStack上频繁出现虚拟机创建失败的情况,查看日志定位到问题出在neutron-server向keystone认证token失败. 故障原因 Keystone所使用的Mem ...

  2. BZOJ 4479: [Jsoi2013]吃货jyy

    一句话题意:求必须包含某K条边的回路(回到1),使得总权值最小 转化为权值最小的联通的偶点 令F[i]表示联通状态为i的最小权值,(3^n状压)表示不在联通块内/奇点/偶点,连边时先不考虑必选的边的度 ...

  3. 贪心 - [POI2006]ORK-Ploughing

    [POI2006]ORK-Ploughing 描述 Byteasar 想耕种他那块矩形的田,他每次能耕种矩形的一边(上下左右都行),在他每次耕完后,剩下的田也一定是矩形,每块小区域边长为 1,耕地的长 ...

  4. Oracle 了解 DDL 操作与 REDO 的关系

    目录 了解 DDL 操作与 REDO 的关系 DDL是否会产生REDO 通过 10046 trace 来分析create 和drop 如果drop失败,redo的变化 了解 DDL 操作与 REDO ...

  5. 突然想看单纯形 BZOJ3265 志愿者招募加强版

    本来的版本是可以差分之后建图利用网络流,这个题是板子题,就当存个板子,嘻嘻嘻 讲解可以到卿学姐的算法讲堂 https://www.bilibili.com/video/av7847726?from=s ...

  6. Unity3D - UGUI组件的中英文对照

  7. 解决Failed with error: unable to access 'https://git.coding.net/chenmi1234/lianpos.git/': Couldn't resolve host 'git.coding.net'

    代码改变世界 github push 出现问题 Failed with error: unable to access 'https://git.coding.net/chenmi1234/lianp ...

  8. JDBC 学习笔记(三)—— JDBC 常用接口和类,JDBC 编程步骤

    1. JDBC 常用接口和类 DriverManager 负责管理 JDBC 驱动的服务类,程序中主要的功能是获取连接数据库的 Connection 对象. Connection 代表一个数据库连接对 ...

  9. ideaaaaaaaaa

    数据库proxy:可以用作自动化数据逆向SQL test4j/jtester:

  10. 关于scarpy的一些说明

    一  scrapy添加代理 1 内置代理:os.environ. 固定格式,不推荐 os.environ['http_proxy'] = "http://root:woshiniba@192 ...