Fork me on GitHub

使用Spring访问数据

统一的数据访问异常层次体系

为了统一和简化相关的数据访问操作,J2EE核心模式提出了DAO(Data Access Object,数据访问对象)模式。使用DAO模式,可以完全分离数据的访问和存储,很好地屏蔽了各种数据访问方式的差异性。不论数据存储在普通的文本文件或者csv文件,还是关系数据库(RDBMS)或者LDAP(Lightweight Directory Access Protocol,轻量级目录访问协议)系统中,使用DAO模式访问数据的客户端代码可以完全忽视这种差异,而以统一的接口来访问相应数据。

当数据访问接口的实现类随着需求而发生变化时,客户端代码(service层代码)可以完全忽视这种变化,唯一需要变动的地方可能只是Factory对象的几行代码,甚至只是IoC容器配置文件中简单的class类型替换而已,客户端代码无需任何变动。所以,DAO模式对屏蔽不同数据访问机制的差异性起到举足轻重的作用。

异常导致接口无法定义

那么问题来了:
当DAO实现类出现异常的时候,如何捕获SQLException呢?如果直接在DAO实现类处理掉的话,客户端代码就不知道在数据访问期间发生的问题。所以只好先将SQLException抛给客户端。但是这样会产生2个问题:
问题1:
我们的数据访问接口对于客户端来说是通用的,不管数据访问对象因为数据访问机制的不同而如何变更,客户端代码不应该受其牵连。但是,现在因为使用JDBC做数据访问,需要抛出特定的SQLException,那么客户端代码就需要捕捉该异常并做相应的处理。这是与数据访问对象模式的设计初衷相背离的。
问题2:
在引入另一种数据访问机制时,问题更是接踵而来。当换了一个Dao实现,需要抛出另一个Exception,例如:NamingException,如果要保证方法被实现就需要更改方法签名。这样更糟糕了,我们把统一的访问接口给改了。
因为数据访问机制的不同,我们的数据访问接口的定义变成了空中楼阁,我们无法最终定义并确定这个接口。

Spring 数据访问异常层次体系

Spring 框架中统一的异常层次体系所涉及的大部分异常类型都定义在org.springframework.dao包中,处于这个体系的所有异常类型均以org.springframework.dao.DataAccessException为“统领”,然后根据职能划分为不同的异常子类型,总体上看,整个异常层次体系如下图所示:

JDBC API 的最佳实践

基于TemplateJDBC使用方式

由于JDBC API在使用中容易出错,使用繁琐;为了解决它在实际使用中的尴尬局面,Spring框架提出了org.springframework.jdbc.core.jdbcTemplate作为数据访问的Helper类。抓住JdbcTemplate,就抓住了Spring框架JDBC API最佳实践的核心。
JdbcTemplate主要关注如下两个事情:

  • 封装所有基于JDBC的数据访问代码,以统一的格式和规范来使用JDBC API。所有基于JDBC的数据访问需求现在全部通过JdbcTemplate进行,从而避免了让烦琐易错的基于JDBC API的数据访问代码散落于系统各处。
  • 对SQLException所提供的异常信息在框架内进行统一转译,将基于JDBC的数据访问异常纳入Spring自身的异常层次体系中,统一了数据接口的定义,简化了客户端代码对数据访问异常的处理。

JdbcTemplate主要通过模板方法模式对基于JDBC的数据访问代码进行统一封装。
模板方法模式:主要用于对算法或者行为逻辑进行封装,即如果多个类中存在某些相似的算法逻辑或者行为逻辑,可以将这些相似的逻辑提取到模板方法类中实现,然后让相应的子类根据需要实现某些自定义逻辑。

「真诚赞赏,手留余香」