Spring编程式事务管理注意事项?

7

Spring支持编程式事务,可以对事务管理进行精细化控制。根据Spring文档,我们可以通过以下方式使用编程式事务管理:

1. 利用Spring的TransactionTemplate:

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

protected void doInTransactionWithoutResult(TransactionStatus status) {
    try {
        updateOperation1();
        updateOperation2();
    } catch (SomeBusinessExeption ex) {
        status.setRollbackOnly();
    }
} });

2. 直接利用 PlatformTransactionManager(将 PlatformTransactionManager 实现注入到 DAO 中):

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

//txManager is a reference to PlatformTransactionManager
TransactionStatus status = txManager.getTransaction(def);
try {
  updateOperation1();
  updateOperation2();
}
catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

为了简化,我们假设我们正在处理JDBC数据库操作。
我想知道在第二个代码片段中发生的任何数据库操作,无论是通过JDBCTemplate还是JDBCDaoSupport实现的,如果没有,则该操作实际上未在任何事务中执行,对吗?
我的分析是,如果我们不使用JDBCTemplate或JDBCDaoSupport,则不可避免地会从数据源管理中创建/检索连接。我们获取的连接当然不是由PlatformTransactionManager用于管理事务的连接。
我查看了Spring源代码并浏览了相关类,发现PlatformTransactionManager将尝试检索包含在ConnectionHolder中的连接,后者返回自TransactionSynchronizationManager检索的。我还发现,JDBCTemplate和JDBCDaoSupport也尝试使用类似的例程从TransactionSynchronizationManager获取连接。
因为TransactionSynchronizationManager管理许多资源,包括每个线程的连接(基本上使用Threadlocal来确保一个线程获取其自己唯一的受管理资源的实例)
所以我认为由PlatformTransactionManager和JDBCTemplate或JDBCDaoSupport检索到的连接是相同的,这可以解释Spring编程事务如何确保updateOperation1()、updateOperation2()受到事务保护。
我的分析是否正确?如果是,为什么Spring文档没有强调这个警告?
1个回答

4

没错,这是正确的。

任何使用原始 Connection 的代码都应该以特定方式从 DataSource 中获取它们,以便参与由 Spring 管理的事务 (12.3.8 DataSourceTransactionManager):

应用程序代码需要通过 DataSourceUtils.getConnection(DataSource) 来检索 JDBC 连接,而不是使用 Java EE 的标准 DataSource.getConnection。

另一个选择(如果您无法更改调用 getConnection() 的代码)是将您的 DataSource 包装在 TransactionAwareDataSourceProxy 中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接