使用Oracle JDBC驱动程序进行Spring XA事务

时间:2011-05-26 07:04:38

标签: oracle spring jta jdbctemplate oci

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

  1. 使用OCI JDBC驱动程序和oracle.jdbc.xa.client.OracleXADataSource。此数据源由UCP连接池数据源包围 - oracle.ucp.jdbc.PoolDataSourceImpl
  2. 使用spring JdbcTemplate执行查询。
  3. 使用Bitronix事务管理器处理分布式事务
  4. 使用注释的Spring声明式事务
  5. 我面临的问题是使用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;
    

    <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>

    有关可能导致查询未在交易中执行的原因的任何建议吗?

    更新1

    添加使用jdbcTemplate执行查询的方法并在结尾处抛出异常

    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;

    更新2

    Oracle JDBC Developer Guide提及

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

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

    更新3

    如果我使用bitronix池化数据源而不是oracle ucp PoolDataSource,则事务有效。使用bitronix PoolingDataSource为bitronix提供了将自动提交状态设置为false的机会。将调查更多来计算两者之间的差异。

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

也就是说,关于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()方法。在返回它们之前,将auto commit设置为false。您还可以反编译JDBC驱动程序代码,以查看PoolDataSourceImpl是否已包含类似的内容但显然不包含。