DAO Support

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

The Data Access Object (DAO) support in Spring is aimed at making it easy to work with data access technologies (such as JDBC, Hibernate, or JPA) in a consistent way. This lets you switch between the aforementioned persistence technologies fairly easily, and it also lets you code without worrying about catching exceptions that are specific to each technology.

Consistent Exception Hierarchy

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

Spring provides a convenient translation from technology-specific exceptions, such as SQLException to its own exception class hierarchy, which has DataAccessException as the root exception. These exceptions wrap the original exception so that there is never any risk that you might lose any information about what might have gone wrong.

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

In addition to JDBC exceptions, Spring can also wrap JPA- and Hibernate-specific exceptions, converting them to a set of focused runtime exceptions. This lets you handle most non-recoverable persistence exceptions in only the appropriate layers, without having annoying boilerplate catch-and-throw blocks and exception declarations in your DAOs. (You can still trap and handle exceptions anywhere you need to though.) As mentioned above, JDBC exceptions (including database-specific dialects) are also converted to the same hierarchy, meaning that you can perform some operations with JDBC within a consistent programming model.

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

The preceding discussion holds true for the various template classes in Spring’s support for various ORM frameworks. If you use the interceptor-based classes, the application must care about handling HibernateExceptions and PersistenceExceptions itself, preferably by delegating to the convertHibernateAccessException(..) or convertJpaAccessException(..) methods, respectively, of SessionFactoryUtils. These methods convert the exceptions to exceptions that are compatible with the exceptions in the org.springframework.dao exception hierarchy. As PersistenceExceptions are unchecked, they can get thrown, too (sacrificing generic DAO abstraction in terms of exceptions, though).

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

The following image shows the exception hierarchy that Spring provides. (Note that the class hierarchy detailed in the image shows only a subset of the entire DataAccessException hierarchy.)

DataAccessException

Annotations Used to Configure DAO or Repository Classes

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

The best way to guarantee that your Data Access Objects (DAOs) or repositories provide exception translation is to use the @Repository annotation. This annotation also lets the component scanning support find and configure your DAOs and repositories without having to provide XML configuration entries for them. The following example shows how to use the @Repository annotation:

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 存储库:

Any DAO or repository implementation needs access to a persistence resource, depending on the persistence technology used. For example, a JDBC-based repository needs access to a JDBC DataSource, and a JPA-based repository needs access to an EntityManager. The easiest way to accomplish this is to have this resource dependency injected by using one of the @Autowired, @Inject, @Resource or @PersistenceContext annotations. The following example works for a JPA repository:

  • 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,如下例所示:

If you use the classic Hibernate APIs, you can inject SessionFactory, as the following example shows:

  • 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

The last example we show here is for typical JDBC support. You could have the DataSource injected into an initialization method or a constructor, where you would create a JdbcTemplate and other data access support classes (such as SimpleJdbcCall and others) by using this DataSource. The following example autowires a 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 以了解如何配置应用程序上下文来利用这些注释。

See the specific coverage of each persistence technology for details on how to configure the application context to take advantage of these annotations.