DAO Support

Spring 中的数据访问对象 (DAO) 支持旨在使以一致的方式使用数据访问技术(例如 JDBC、Hibernate 或 JPA)变得容易。这使你可以相对轻松地在上述持久性技术之间切换,而且它还能让你在不用担心捕获特定于每种技术异常的情况下编写代码。

Consistent Exception Hierarchy

Spring 提供从特定于技术的异常(如 SQLException)到其自身异常类层次结构的便捷转换,其根异常为 DataAccessException。这些异常包装了原始异常,因此不存在丢失可能有误信息的不良风险。

除 JDBC 异常外,Spring 还可以包装 JPA 和 Hibernate 特定的异常,并将其转换为一系列集中的运行时异常。这让你仅在适当的层处理大多数不可恢复的持久性异常,而无需在 DAO 中编写令人厌烦的样板捕获和抛出块及异常声明。(你仍然可以在任何需要的地方捕获和处理异常。)如上所述,JDBC 异常(包括特定于数据库的方言)也转换为相同的层次结构,这意味着你可以在一致的编程模型中对 JDBC 执行某些操作。

上述讨论适用于 Spring 支持各种 ORM 框架中各种模板类。如果你使用基于拦截器的类,那么应用程序必须注意自行处理 HibernateExceptionsPersistenceExceptions,最好分别委派给 SessionFactoryUtilsconvertHibernateAccessException(..)convertJpaAccessException(..) 方法。这些方法将异常转换为与 org.springframework.dao 异常层次结构中的异常兼容的异常。由于 PersistenceExceptions 未受检,因此也可以抛出它们(但在异常方面牺牲了通用的 DAO 抽象)。

下图显示了 Spring 提供的异常层次结构。(请注意,图片中详述的类层次结构仅显示 DataAccessException 整个层次结构的一部分。)

DataAccessException

Annotations Used to Configure DAO or Repository Classes

保证你的数据访问对象 (DAO) 或存储库提供异常转换的最佳途径是使用 @Repository 注解。该注解还允许组件扫描支持在不必须为其提供 XML 配置项的情况下查找和配置 DAO 和存储库。下例显示了如何使用 @Repository 注解:

Java
@Repository (1)
public class SomeMovieFinder implements MovieFinder {
	// ...
}
1 The @Repository annotation.
Kotlin
@Repository (1)
class SomeMovieFinder : MovieFinder {
	// ...
}
2 The @Repository annotation.

根据所使用持久性技术,任何 DAO 或存储库实现都需要访问持久性资源。例如,基于 JDBC 的存储库需要访问 JDBC 的 DataSource,而基于 JPA 的存储库需要访问 EntityManager。实现这一目标的最简单方法是使用 @Autowired@Inject@Resource@PersistenceContext 注解之一注入此资源依赖项。下例适用于 JPA 存储库:

  • Java

  • Kotlin

@Repository
public class JpaMovieFinder implements MovieFinder {

	@PersistenceContext
	private EntityManager entityManager;

	// ...
}
@Repository
class JpaMovieFinder : MovieFinder {

	@PersistenceContext
	private lateinit var entityManager: EntityManager

	// ...
}

如果你使用经典 Hibernate API,你可以注入 SessionFactory,如下例所示:

  • Java

  • Kotlin

@Repository
public class HibernateMovieFinder implements MovieFinder {

	private SessionFactory sessionFactory;

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	// ...
}
@Repository
class HibernateMovieFinder(private val sessionFactory: SessionFactory) : MovieFinder {
	// ...
}

我们在此展示的最后一个示例用于典型 JDBC 支持。你可能会将 DataSource 注入初始化方法或构造函数中,在其中你将使用此 DataSource 创建一个 JdbcTemplate 及其他数据访问支持类(例如 SimpleJdbcCall 及其他)。下例自动注入 DataSource

  • Java

  • Kotlin

@Repository
public class JdbcMovieFinder implements MovieFinder {

	private JdbcTemplate jdbcTemplate;

	@Autowired
	public void init(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	// ...
}
@Repository
class JdbcMovieFinder(dataSource: DataSource) : MovieFinder {

	private val jdbcTemplate = JdbcTemplate(dataSource)

	// ...
}

请参阅每种持久性技术的具体 coverage 以了解如何配置应用程序上下文来利用这些注释。