对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

使用事务同步资源

如何创建不同的事务管理器,以及它们如何与需要同步到事务的相关资源进行关联(例如 DataSourceTransactionManager 与 JDBC DataSource 关联,HibernateTransactionManager 与 Hibernate SessionFactory 关联,等等),现在应该已经清楚了。本节将介绍应用程序代码(直接或间接地通过使用持久化 API,如 JDBC、Hibernate 或 JPA)如何确保这些资源被正确地创建、复用和清理。本节还将讨论如何通过相应的 TransactionManager(可选地)触发事务同步。spring-doc.cadn.net.cn

高级同步方法

首选的方法是使用 Spring 基于模板的高级持久化集成 API,或者结合事务感知的工厂 Bean 或代理来使用原生 ORM API,以管理原生资源工厂。这些事务感知的解决方案在内部处理资源的创建与复用、清理、资源的可选事务同步以及异常映射。因此,用户的数据访问代码无需处理这些任务,而可以专注于纯粹的非样板式持久化逻辑。通常情况下,对于 JDBC 访问,您可以使用原生 ORM API,也可以采用基于 JdbcTemplate 的模板方法。这些解决方案将在本参考文档的后续章节中详细说明。spring-doc.cadn.net.cn

低级同步方法

诸如 DataSourceUtils(用于 JDBC)、EntityManagerFactoryUtils(用于 JPA)、 SessionFactoryUtils(用于 Hibernate)等类存在于较低的层次。当你希望应用程序代码直接处理原生持久化 API 的资源类型时, 可以使用这些类来确保获取到由 Spring 框架正确管理的实例, (可选地)同步事务,并将过程中发生的异常正确地映射到一致的 API。spring-doc.cadn.net.cn

例如,在 JDBC 的情况下,您可以使用 Spring 的 getConnection() 类,而不是传统的 JDBC 方法直接调用 DataSource 上的 org.springframework.jdbc.datasource.DataSourceUtils 方法,如下所示:spring-doc.cadn.net.cn

Connection conn = DataSourceUtils.getConnection(dataSource);

如果现有事务已经有一个连接与其同步(关联),则返回该连接实例。否则,该方法调用会触发创建一个新的连接,该连接(可选地)与任何现有事务同步,并可在同一事务中被后续重复使用。如前所述,任何 SQLException 都会被封装为 Spring 框架的 CannotGetJdbcConnectionException 异常,这是 Spring 框架中非受检 DataAccessException 异常体系的一部分。这种方法比直接从 SQLException 中获取的信息更加丰富,并确保了在不同数据库之间、甚至不同持久化技术之间的可移植性。spring-doc.cadn.net.cn

此方法在不使用 Spring 事务管理的情况下也可以工作(事务同步是可选的),因此无论您是否使用 Spring 进行事务管理,都可以使用它。spring-doc.cadn.net.cn

当然,一旦你使用了 Spring 的 JDBC 支持、JPA 支持或 Hibernate 支持,通常就不再愿意直接使用 DataSourceUtils 或其他辅助类,因为你更倾向于通过 Spring 提供的抽象层进行开发,而不是直接使用底层的相关 API。例如,如果你使用 Spring 的 JdbcTemplatejdbc.object 包来简化 JDBC 的使用,那么正确的连接获取会在幕后自动完成,你无需编写任何特殊代码。spring-doc.cadn.net.cn

TransactionAwareDataSourceProxy

在最底层,存在 TransactionAwareDataSourceProxy 类。这是一个目标 DataSource 的代理类,它包装了目标 DataSource,以增加对 Spring 管理的事务的感知能力。在这方面,它类似于 Jakarta EE 服务器所提供的事务型 JNDI DataSourcespring-doc.cadn.net.cn

你几乎永远都不需要或不应该使用这个类,除非必须调用现有代码,并向其传递一个标准 JDBC DataSource 接口的实现。在这种情况下,该代码可能是可用的,但同时又参与了 Spring 管理的事务。你可以通过使用前面提到的更高层次的抽象来编写你的新代码。spring-doc.cadn.net.cn