Spring 定义的数据访问异常体系相比于 JDBC 的 SQLException 要丰富的多,并且没有与特定的持久化方式相关联。 持久化机制与数据访问层隔离开来。

DataAccessException 非检查型异常,不强制进行捕获,因为 Spring 认为触发异常的很多问题是不能在 catch 代码块中进行捕获的,如连接信息有误、语法错误等异常(就算捕获了,也不能做任何处理)。是否要捕获异常取决于开发人员。

模板方法模式

构造器 @Inject 注解 需要加入依赖:

1
2
3
4
5
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>

Spring JDBC

Spring JDBC 框架承担了必要的资源管理异常处理工作,简化了 JDBC 代码, 只需要关注必要的数据库读写代码即可。

Spring 将数据访问的样板代码抽象到模板类中。

Spring 为 JDBC 提供了三个模板类:

  • JdbcTemplate:最基本的 Spring JDBC 模板,支持简单的 JDBC 数据库访问功能以及基于索引参数的查询(赋值的顺序与 SQL 语句占位符的顺序要一致) Spring 3.1 开始,支持 Java 5 的自动装箱、泛型以及可变参数列表等特性来简化 JDBC 模板的使用
  • NamedParameterJdbcTemplate:可以将值以命名参数的形式绑定到 SQL 中(相对于索引参数)

Spring 与 Hibernate 的集成

Spring 提供了与 JDBC 类似的模板类 HibernateTemplate,能够保证每个事务使用同一个 Session, 弊端在于 Repository 的实现与 Spring 耦合。

可以直接使用 Hibernate 的上下文 Session Contextual Session, 其实 Hibernate 等持久化框架已经达到了和模板类类似的功能,如获取链接,创建语句,管理事务,关闭资源等,因此直接使用也是比较方便的。

需要声明一个 org.springframework.orm.hibernate4.LocalSessionFactoryBean bean(对象关系映射既可以通过注解,也可以通过配置文件声明), 继承自 Spring 的 FactoryBean, 会产生 Hibernate 的 SessionFactory

但是不使用 Spring 提供的模板类,问题就是 Repository 实现类会抛出 Hibernate 相关的异常,而不是 Spring 定义的非检查型异常。解决方案是:定义一个 PersistenceExceptionTranslationPostProcessor bean。

PersistenceExceptionTranslationPostProcessor是一个bean 后置处理器(bean post-processor),它会在所有拥有@Repository注解的类上添加一个通知器(advisor),这样就会捕获任何平台相关的异常并以Spring非检查型数据访问异常的形式重新抛出。

@Repository 注解

@Repository注解,这会为我们做两件事情。首先,@Repository是Spring的另一种构造性注解,它能够像其他注解一样被Spring的组件扫描所扫描到, 表明在组件扫描的时候会自动创建。这样就不必明确声明HibernateSpitterRepository bean了,只要这个Repository类在组件扫描所涵盖的包中即可。

除了帮助减少显式配置以外,@Repository还有另外一个用处。让我们回想一下模板类,它有一项任务就是捕获平台相关的异常,然后使用Spring统一非检查型异常的形式重新抛出。