2

我正在尝试使用 bitronix 事务管理器启用分布式事务。配置细节包括

  1. 使用 OCI JDBC 驱动程序和 oracle.jdbc.xa.client.OracleXADataSource。此数据源由 UCP 连接池数据源环绕 - oracle.ucp.jdbc.PoolDataSourceImpl
  2. 使用 spring JdbcTemplate 执行查询。
  3. 使用 Bitronix 事务管理器处理分布式事务
  4. 使用注解的 Spring 声明式事务

我面临的问题是使用 JDBCTemplate 执行的查询没有在事务中执行。我的测试用例使用 JDBCTemplate 执行两个查询,并且当方法在查询执行后引发运行时异常时,它们不会回滚。我还可以看到连接的自动提交状态设置为 true。

<tx:annotation-driven transaction-manager="distributedTransactionManager"/>

<bean id="distributedTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="bitronixTransactionManager"/>
    <property name="userTransaction" ref="bitronixTransactionManager"/>
    <property name="allowCustomIsolationLevels" value="true"/>
</bean>

<bean id="bitronixTransactionManager" factory-method="getTransactionManager"
      class="bitronix.tm.TransactionManagerServices" depends-on="bitronixConfiguration"
      destroy-method="shutdown">
</bean>

The data source is created as follows

    PoolDataSourceImpl pds = new PoolDataSourceImpl();
    try {
        pds.setConnectionPoolName(dataSourceName);
        pds.setConnectionFactoryClassName("oracle.jdbc.xa.client.OracleXADataSource");
        pds.setConnectionFactoryProperties(getOracleDataSourceProperties());
        pds.setDataSourceName(dataSourceName);
        pds.setServerName("v-in-sd-tst-12");
        pds.setPortNumber(1521);
        pds.setUser("ForTestCasesAmit");
        pds.setPassword("adept");
        pds.setMinPoolSize(10);
        pds.setMaxPoolSize(100);
        pds.setMaxIdleTime(1800);

        pds.startPool();
    } catch (SQLException e) {
        throw new RuntimeException("Cannot create project datasource " + dataSourceName, e);
    }
    return pds;

关于查询未在事务中执行的原因的任何建议?

更新 1

添加使用 jdbcTemplate 执行查询并在最后引发异常的方法

@Transactional(propagation = Propagation.REQUIRED)
public void execute() {
    System.out.println("Starting with the service method");
    jdbcTemplateForDSOne.update("UPDATE T1 SET COL1 = 'Date1' WHERE COL2 = 1");

    jdbcTemplateForDSOne.update("UPDATE T1 SET COL1 = 'Start Date1' WHERE COL2 = 2");

    waitForUserInput();
    throw new RuntimeException("Rollback Now");
}

更新 2

Oracle JDBC 开发人员指南提到

“在 Oracle Database 10g 之前的所有版本中,从 XAConnection 获得的连接的默认自动提交状态为 false。从 Oracle Database 10g 开始,默认状态为 true。”

我正在使用 Oracle 11g r2。知道在使用分布式事务将自动提交状态设置为 false 时应该进行哪些配置更改?

更新 3

如果我使用 bitronix 池数据源而不是 oracle ucp PoolDataSource,则这些事务有效。使用 bitronix PoolingDataSource 使 bitronix 有机会将自动提交状态设置为 false。将进行更多调查以找出两者之间的区别。

4

2 回答 2

0

您是否有包含此代码的方法,使用 @Transactional 注释或定义了任何会告诉 Spring 在事务中执行此方法的方面?

于 2011-05-26T08:02:02.430 回答
0

据我所知,它们是在事务中执行的,但事务不是您所期望的。当autoCommitis时true,每个查询都成为一个事务。您必须正确配置连接以避免这种情况。

也就是说,关于 XA 的评论:XA 在网络问题和超时等极端情况下不起作用。也就是说,它会工作 99.9995% 次,但在一些关键情况下,它不会,而那些是你关心的情况。

确保当 XA 最终使您失败时,您的数据结构不会损坏。

我建议不要评估 XA,而是评估允许再次运行事务的方法。示例:您想将一些记录从数据库 A 传输到 B。因此,您读取行,FOR UPDATE并且对于每个传输的行,您将processed列设置为 true。

另一方面,您只添加尚不存在的行。

B 中的 tx 提交后,删除 A 中的行where processed = 'true'或以其他方式标记它们。

这意味着您可以根据需要经常运行它。

[编辑]

要禁用自动提交,您必须调用con.setAutoCommit(false);问题当然是您使用的是 Spring,因此您永远不会在任何地方明确请求连接。

我的建议:扩展PoolDataSourceImpl和覆盖各种get*Connection()方法。在返回它们之前,将自动提交设置为 false。您还可以反编译 JDBC 驱动程序代码以查看是否PoolDataSourceImpl已经包含类似的内容,但显然它没有。

于 2011-05-26T09:41:35.503 回答