Spring对DAO的支持
Spring对DAO的支持
近几年,数据库持久化技术得到了长足的发展,Hibernate、MyBatis、JPA等成为持久层争放异彩的实现技术。一个典型的DAO应用实例如下图:

在UserDao中定义访问User数据对象的接口,并使用具体的持久化技术实现期中的接口方法,业务层通过UserDao操作数据,这样就使得业务层与具体的持久化实现技术实现了解耦。
使用Dao抽象层带来的好处:
1.使得业务层与具体的持久化实现技术实现了解耦,使得代码高内聚,低耦合。
2.面向接口编程使得代码可以很容易的构建模拟对象,方便展开单元测试。
Spring希望以统一的方式整合不同的持久化实现技术,即使得用户以统一的方式进行调用和事务控制,避免具体的持久化实现侵入到业务层代码。为了实现这个目标,Spring统一了各个持久化实现技术的异常体系(每个持久化技术都有自己的异常体系),并且提供了统一的数据访问模板,方便用户使用。
统一的异常体系
背景
很多正统API或者框架中,检查型异常被过多的使用,以至于我们使用其API时,代码中充斥着try/catch样板式代码。在很多时候,这些try/catch除了记录异常信息以外,很难做一些实际工作(引发异常的问题往往是不可恢复的,如:数据库连接失败、SQL语句错误等),强制开发人员捕获此类检查型异常除了限制开发人员以外,并没有做有价值的东西。
Spring的Dao异常体系
为解决此类问题,Spring将各个框架的异常(特别是受检异常)转化为其统一的异常体系。这些异常都继承于DataAccessException,而DataAccessException本身又继承于NestedRuntimeException,这样将受检异常转化为非受检异常。而NestedRuntimeException以嵌套方式封装了异常的源信息,开发人员随时可以使用getCause()获取异常原因。
其异常体系的顶层异常如下:

| 异常 | 说明 |
|---|---|
CleanupFailureDataAccessException |
Dao操作执行成功,但在释放数据资源时发生异常,如:关闭Connection异常 |
ConcurrencyFailureException |
并发数据操作时发生异常:锁无法获取、死锁异常等 |
DataAccessResourceFailureException |
获取数据资源时发生异常:获取Connection失败、获取Hibernate Session失败等。 |
DataRetrievalFailureException |
获取数据失败,找不到主键、使用错误索引等。 |
DataSourceLookupFailureExcption |
无法从JNDI中查找数据源 |
DataIntegrityViolationException |
数据违反了一致性约束:插入重复主键、引用不存在的外键等 |
InvalidDataAccessApiUsageException |
不正确的调用持久化技术API导致的异常:如Spring JDBC中查询对象,必须在调用前进行编译,如果忘记编译则会导致异常。 |
InvalidDataAccessResourceUsageException |
访问数据源时调用了不正确的方法导致的异常:如SQL语句错误 |
PermissionDeniedDataAccessException |
权限不足引发的异常 |
UncategorizedDataAccessException |
其他为分类的异常 |
该异常体系具有高度可扩展性。为进一步细化错误问题域,Spring对顶层异常进行了细分。例如:光是InvalidDataAccessResourceUsageException就有十多个子类。如BadSqlGrammarException对应JDBC异常的语法错误,HibernateQueryException对应Hibernate查询异常。

异常转换的实现
JDBC的异常转换
传统的JDBC API在发生数据操作异常时机会都会抛出SQLException,并将异常细节信息封装在异常属性中。用户通过getErrorCode()获取错误码,该错误码与数据库紧密相关或通过getStateCode()获取SQL状态码。Spring根据错误码和SQL状态码将SQLException转化为其DAO异常体系中的相应异常。

其他持久化技术的异常转换
由于每个持久化技术都有其语义明确的异常体系,所以这些异常转化为Spring的异常体系相对轻松些。Spring同样为每个持久化技术都提供的定制的异常转换器。
| ORM
| 持久化技术 | 异常转换器 |
|---|---|
Hibernate |
org.springframework.orm.hibernate5.SessionFactoryUtils |
JPA |
org.springframework.orm.jpa.EntityManagerFactoryUtils |
注:MyBatis使用与JDBC相同的异常体系,因此与JDB异常转换相同
统一的数据访问模板
背景
参见 Spring理念 一节中的相关介绍。
不同持久化技术的使用模板
Spring为各种持久化技术都提供了简化操作模板和回调,在回调中编写具体的数据操作逻辑,而获取连接、处理异常、释放连接交由模板代码自动完成。这使得用户专注于业务代码,从单调繁杂的无关处理中解脱。
Spring提供的模板如下:
| ORM
| 持久化技术 | 模板类 |
|---|---|
Hibernate |
org.springframework.orm.hibernate5.HibernateTemplate |
JPA |
org.springframework.orm.jpa.JpaTemplate(已废弃,使用EntityManager) |
JDBC |
org.springframework.jdbc.core.JdbcTemplate |
如果直接使用模板类,则需要在Dao中定义模板对象,并提供数据源。Spring为减少这一工作同样提供了支持类,用户只需要扩展这些支持类就可以直接使用模板类。
浙公网安备 33010602011771号