9.4. 使用资源同步的事务

现在应该比较清楚的是:不同的事务管理器是如何创建的,以及它们如何被连接到相应的需要被同步到事务的资源上(例如,DataSourceTransactionManager 对应到JDBC DataSourceHibernateTransactionManager 对应到Hibernate的 SessionFactory 等)。可是,剩下的问题是,直接或间接地使用一种持久化API(JDBC、Hibernate、JDO等)的应用代码,如何确保通过相关的 PlatformTransactionManager 来恰当地获取并操作资源,来满足事务同步,这些操作包括:创建、复用、清理 和 触发(可能没有)。

9.4.1. 高层次方案

首选的方法是使用Spring的高层持久化集成API。这种方式不会替换原始的API,而是在内部封装了资源创建、复用、清理、事务同步以及异常映射等功能,这样用户的数据访问代码就不必关心这些,而集中精力于自己的持久化逻辑。通常,对所有持久化API都采用这种 模板 方法,包括 JdbcTemplateHibernateTemplateJdoTemplate类(这些在这份参考文档后面的章节中详细叙述)。

9.4.2. 低层次方案

在较低层次上,有以下这些类:DataSourceUtils(针对JDBC),SessionFactoryUtils(针对Hibernate),PersistenceManagerFactoryUtils(针对JDO)等等。当对应用代码来说,直接同原始持久化API特有的资源类型打交道是更好的选择时,这些类确保应用代码获取到正确的Spring框架所管理的bean,事务被正确同步,处理过程中的异常被映射到一致的API。

例如,在JDBC环境下,你不再使用传统的调用 DataSourcegetConnection() 方法的方式,而是使用Spring的 org.springframework.jdbc.datasource.DataSourceUtils,像这样:

Connection conn = DataSourceUtils.getConnection(dataSource);

如果已有一个事务及与之关联的connection存在,该实例将被返回。否则,该方法调用将触发起一个新的connection的创建动作,该connection(可选地)被同步到任何现有的事务,并可以在同一事务范围内被后续的调用复用。正如上面提到的,这个过程有一个额外的好处,就是任何 SQLException将被包装为Spring框架的 CannotGetJdbcConnectionException,该类是Spring框架的unchecked的DataAccessExceptions层次体系中的一员。这将给你比从 SQLException 中简单所得更多的信息,而且保证了跨数据库——甚至其他持久化技术——的移植性。

应该指出的是,这些类同样可以在没有Spring事务管理的环境中工作良好(事务同步能力是可选的),所以无论你是否使用Spring的事务管理,你都可以使用这些类。

当然,一旦你用过Spring的JDBC支持或Hibernate支持,你一般就不再会选择 DataSourceUtils 或是别的辅助类了,因为你会更乐意与Spring抽象一起工作,而不是直接使用相关的API。例如,如果你使用Spring的 JdbcTemplatejdbc.object 包来简化使用JDBC,Spring会在幕后替你正确地获取连接,而你不需要写任何特殊代码。

9.4.3.  TransactionAwareDataSourceProxy

工作在最底层的是 TransactionAwareDataSourceProxy 类。这是一个对目标 DataSource 的代理,它包装了目标 DataSource,提供对Spring管理事务的可知性。在这点上,它类似于一个J2EE服务器提供的事务性JNDI DataSource

该类应该永远不需要被应用代码使用,除非现有代码存在需要直接传递一个标准的JDBC的 DataSource 的情况。这时可以通过参与Spring管理事务让这些代码仍然有用。书写新的代码时,首选的方法是采用上面提到的Spring高层抽象。