说说 Spring DAO 的异常体系

Spring 提供了一套和实现技术无关的 、 面向 DAO 层语义级别的异常体系,内部经过转换器将不一样持久化技术的异常转换成 Spring 的异常,实现统一管理。spring

1 异常体系

不少正统的 AP中,使用了过多的检查型异常,以至于在使用 API 时,代码中充斥了大量 try/catch 样板式的代码 。 大多数状况下,这些 catch 代码段除了记录日志外,并无作多少其它有益的工做。数据库

好比 JDK 中的 JDBC API,你们都说很差用,由于检查型异常泛滥,许多异常处理代码喧宾夺主地侵入到业务代码中,从而破坏了总体代码的整洁与优雅 。设计模式

Spring 在 org.springframework.dao 中提供了一套优雅的 DAO 异常体系, 这些异常都继承自 DataAccessExceptionDataAccessException 继承自NestedRuntimeException, NestedRuntimeException 异常以嵌套的方式封装了源异常 。 所以,虽然不一样的持久化技术的特定异常被转换到 Spring 的 DAO 异常体系中,但咱们能够经过 getCause() 方法获取原始异常信息 。并发

这套异常体系从 DAO 的抽象层次上定义了异常目录树,它使得开发者能够很容易地关注某个特定的语义异常。而 JDBC 的 SQLException 过于底层,并且与具体数据库强相关(好比 getErrorCode()),不只很差编码,并且很难移植。工具

Spring 创建了异常分类目录,以适当的颗粒度划分了异常类型。这样作的好处是:编码

  • 开发者能够从底层繁琐复杂的技术细节中解脱出来。
  • 开发者能够选择本身感兴趣的异常进行处理 。

DataAccessException 下有这些异常子类:hibernate

异常子类 说明
CleanupFailureDataAccessException 执行 DAO 操做成功,但在释放数据资源时发生异常,如关闭 Connection 时发生异常。
ConcurrencyFailureException 并发地操做数据时发生异常,如没法获取乐观锁或悲观锁时、死锁引起的失败等场景。
DataAccessResourceFailureException 访问数据资源失败,如没法获取数据链接,没法获取 Hibernate 的会话等场景。
DataRetrievalFailureException 获取数据失败,如找不到对应主键的数据或使用了错误的列索引等场景。
DataSourceLookupFailureException 没法从 JNDI 中查找到数据源。
DataIntegrityViolationException 数据操做违反了数据一致性限制时抛出,如插入重复的主键或引用不存在的外键场景。
InvalidDataAccessApiUsageException 不正确地调用某一种持久化技术时抛出,如在 Spring JDBC 中查询对象在调用前没有事先进行编译操做,就会抛出该异常。这种异常主要是由于不正确地使用持久化技术而产生的。
InvalidDataAccessResourceUsageException 在访问数据源时使用了不正确的方法时抛出,如写错 SQL 语句。
PermissionDeniedDataAccessException 数据访问权限不足时抛出。如仅拥有只读权限却试图更改数据。
UncategorizedDataAccessException 其它未被分类的异常。

Spring 为了进一步细化错误问题域, 它对上述的这些一级异常类又进行了细分。设计

这套异常体系具备高度的可扩展性,当 Spring 须要对一个新的持久化技术提供支持时,只要为其定义一个对应的子异常便可,这种方式实现了设计模式中的“开闭原则” 。3d

开闭原则( OCP )是面向对象设计中 “ 可复用设计 ” 的基石,是面向对象设计中最重要的原则之一,其它不少的设计原则都是实现开闭原则的一种手段 。 对于扩展是开放的,对于修改是关闭的,这意味着模块的行为是能够扩展的 。 当应用的需求改变时,咱们能够对模块进行扩展,使其具备知足那些改变的新行为 。日志

2 异常转换器

2.1 JDBC

通常状况下,JDBC API 在执行数据操做出现异常时,大都会抛出 SQLException ,SQLException 把异常的细节封装在异常属性中,因此若是但愿了解异常的具体缘由,咱们必须对异常属性进行分析。

SQLException 拥有两个表明异常具体缘由的属性:

属性 类型 说明
错误码 int 与具体数据库相关,调用 getErrorCode() 返回。
SQL 状态码 String 标准错误代码,由 5 个字符组成,调用 getSQLState() 返回。

Spring 会根据错误码和 SQL 状态码将 SQLExeption 转换为对应的 Spring DAO 异常 。 在 org.springframework.jdbc.support 包中定义了 SQLExceptionTranslator 接口,该接口的两个实现类 SQLErrorCodeSQLExceptionTranslator 和 `SQLStateSQLExceptionTranslator
分别负责处理 SQLException 中错误代码和 SQL 状态码的转换工做 。

2.2 其它 ORM 持久化技术

其它 ORM 持久化技术都拥有一个语义明确的异常体系,因此转换相对简单。

**注意:**Spring4 只支持 Hibernate3.6+。

Spring 在 org.springframe.orm 中为所支持的 ORM 技术定义了相应的子包。对应的异常转换器也定义在这些子包中:

ORM 持久化技术 异常转换器
HibernateX,X 可为 三、4 或 5 org.springframework.orm.hibernateX.SessionFactoryUtils
JPA org.springframework.orm.jpa.EntityManagerFactoryUtils
JDO org.springframework.orm.jdo.PersistenceManagerFactoryUtils

这些工具类除了具备异常转换的功能外,在进行事务管理时,还提供了从事务上下文环境中返回相同会话的功能 。

Spring 也支持 myBatis 持久化技术,由于 myBatis 抛出的异常与 JDBC 相同, 都是 SQLException 异常,因此采用了和 JDBC 相同的异常转换器 。

相关文章
相关标签/搜索