20220507 2. Data Access - DAO Support
前言
Spring 中的数据访问对象 (Data Access Object,DAO) 支持旨在以一致的方式轻松使用数据访问技术(例如 JDBC、Hibernate 或 JPA)。这使您可以相当轻松地在上述持久层技术之间切换,并且不必担心捕获特定于各种技术的异常。
一致的异常层次结构
Spring 提供了从特定技术的异常(例如 SQLException
)到其自己的异常类层次结构的方便转换,它将 DataAccessException
作为根异常。这些异常包装了原始异常,不会丢失可能导致出错的任何信息。
除了 JDBC 异常之外,Spring 还可以包装 JPA 和 Hibernate 的异常,将它们转换为一组重点关注的运行时异常。这使您可以仅在适当的层中处理大多数不可恢复的持久层异常,而无需在 DAO 中使用烦人的样板代码捕获和抛出块和异常声明。(您仍然可以在任何需要的地方捕获和处理异常)如上所述,JDBC 异常(包括特定于数据库的方言)也被转换为相同的层次结构,这意味着您可以在一致的编程模型中使用 JDBC 执行某些操作
前面的讨论适用于 Spring 对各种 ORM 框架的支持中的各种模板类。如果您使用基于拦截器的类,应用程序必须关注处理 HibernateExceptions
和 PersistenceExceptions
,最好分别委托给 SessionFactoryUtils
的 convertHibernateAccessException(..)
和 convertJpaAccessException(..)
方法。这些方法将异常转换为与 org.springframework.dao
异常层次结构中的异常兼容的异常。由于 PersistenceExceptions
是非检查异常,它们也可能被抛出(尽管在异常方面牺牲了通用 DAO 抽象)。
下图显示了 Spring 提供的异常层次结构。(请注意,图中详述的类层次结构仅显示了整个 DataAccessException
层次结构的一个子集 )
参考源码
org.springframework.orm.hibernate5.SessionFactoryUtils#convertHibernateAccessException
SessionFactoryUtils
中没有convertJpaAccessException
方法org.springframework.dao.DataAccessException
用于配置 DAO 或存储库(Repository) 类的注解
保证您的数据访问对象 (DAO) 或存储库提供异常转换的最佳方法是使用 @Repository
注解。此注解还允许组件扫描支持查找和配置您的 DAO 和存储库,而无需为它们提供 XML 配置。以下示例显示了如何使用 @Repository
注解:
@Repository
public class SomeMovieFinder implements MovieFinder {
// ...
}
任何 DAO 或存储库实现都需要访问持久层资源,具体取决于所使用的持久层技术。例如,基于 JDBC 的存储库需要访问 JDBC DataSource
,而基于 JPA 的存储库需要访问 EntityManager
。实现这一点的最简单方法是使用 @Autowired
、@Inject
、@Resource
或 @PersistenceContext
注解之一注入此资源依赖关系。以下示例适用于 JPA 存储库:
@Repository
public class JpaMovieFinder implements MovieFinder {
@PersistenceContext
private EntityManager entityManager;
// ...
}
如果您使用经典的 Hibernate API,则可以注入 SessionFactory
,如以下示例所示:
@Repository
public class HibernateMovieFinder implements MovieFinder {
private SessionFactory sessionFactory;
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
// ...
}
至于 JDBC 支持,您可以将 DataSource
注入到初始化方法或构造函数中,您可以使用 DataSource
创建 JdbcTemplate
和其他数据访问支持类(例如 SimpleJdbcCall
)。以下示例自动装配 DataSource
:
@Repository
public class JdbcMovieFinder implements MovieFinder {
private JdbcTemplate jdbcTemplate;
@Autowired
public void init(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// ...
}