“本地事务已经有1个非XA资源:无法添加更多资源”错误

时间:2010-05-20 23:27:09

标签: java hibernate jdbc ejb

在阅读有关此错误的先前问题后,似乎所有人都认为您需要在所有数据源上启用XA。但是:

  1. 如果我不想分发,该怎么办? 交易?如果我愿意,我该怎么办? 开始两个不同的交易 数据库同时,但 在一个数据库上提交事务 并回滚事务 另一个?
  2. 我想知道我的代码如何 实际上发起了分布式 交易。它看起来像我 开始完全分开 每个交易 数据库。
  3. 有关应用程序的信息:

    该应用程序是在Sun Java Application Server 9.1上运行的EJB

    我使用类似下面的spring上下文来设置hibernate会话工厂:

    <bean id="dbADatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="jdbc/dbA"/>
    </bean>
    
    <bean id="dbASessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dbADatasource" />
        <property name="hibernateProperties">
            hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
            hibernate.default_schema=schemaA
        </property>
        <property name="mappingResources">
            [mapping resources...]
        </property>
    </bean>
    
    <bean id="dbBDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="jdbc/dbB"/>
    </bean>
    
    <bean id="dbBSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dbBDatasource" />
        <property name="hibernateProperties">
            hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
            hibernate.default_schema=schemaB
        </property>
        <property name="mappingResources">
            [mapping resources...]
        </property>
    </bean>
    

    两个JNDI资源都是javax.sql.ConnectionPoolDatasoure。它们实际上都指向相同的连接池,但是我们有两个不同的JNDI资源,因为将来两个完全独立的表组可能会移动到不同的数据库。

    然后在代码中,我这样做:

    sessionA = dbASessionFactory.openSession();
    sessionB = dbBSessionFactory.openSession();
    sessionA.beginTransaction();
    sessionB.beginTransaction();
    

    sessionB.beginTransaction()行在这篇文章的标题中产生错误 - 有时候。我在两个不同的sun应用服务器上运行了应用程序。在一个运行它很好,另一个抛出错误。我发现两台服务器的配置方式没有任何区别,尽管它们连接到不同但相当的数据库。

    所以问题是

    1. 为什么上面的代码没有开始 完全独立的交易?
    2. 如何强制它开始 独立交易而不是 分布式交易?
    3. 哪种配置可能导致差异 两个应用程序之间的行为 服务器?
    4. 感谢。

      P.S。堆栈跟踪是:

      Local transaction already has 1 non-XA Resource: cannot add more resources. 
      at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.enlistResource(J2EETransactionManagerOpt.java:124) 
      at com.sun.enterprise.resource.ResourceManagerImpl.registerResource(ResourceManagerImpl.java:144) 
      at com.sun.enterprise.resource.ResourceManagerImpl.enlistResource(ResourceManagerImpl.java:102) 
      at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:216) 
      at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:327) 
      at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:189) 
      at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165) 
      at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158) 
      at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:108) 
      at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82) 
      at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446) 
      at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167) 
      at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142) 
      at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85) 
      at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354) 
      at [application code ...]
      

2 个答案:

答案 0 :(得分:5)

  

1为什么上面的代码没有启动完全独立的事务?

该应用。服务器为您管理事务,如果需要,可以是分布式事务。它会自动征集所有参与者。当只有一个参与者时,您没有注意到与纯JDBC事务有任何区别,但如果有多个参与者,则确实需要分布式事务,因此出现错误。

  

2如何强制它启动独立事务而不是a   分布式交易?

您可以将数据源配置为be XA or Local。 Spring / Hibernate的事务行为也可以配置为使用常规JDBC事务或将事务管理委派给JTA分布式事务管理器。

我建议你将数据源切换到非XA并尝试配置Spring / Hibernate以使用JDBC事务。您应该在documentation中找到相关信息,我怀疑这是要更改的行:

<bean id="txManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />

这实际上意味着您没有使用该应用。服务器分布式事务管理器。

  

3什么配置可能导致两者之间的行为差​​异   两个应用服务器?

如果您的应用程序和配置确实完全相同,这意味着在一种情况下,只有一个参与者加入了dist。交易,而在第二种情况下有两个。一个参与者通常对应于与数据库的一个物理连接。可能是在一种情况下,您在两个不同的数据库上使用两个模式,而在第二种情况下,您在相同的物理数据库上使用两个模式?更可能的解释是数据源在两个应用程序上的配置不同。服务器。

PS:如果您使用JTA分布式事务,则应使用UserTransaction.{begin,commit,rollback}而不是Session上的等效内容。

答案 1 :(得分:1)

  

在阅读有关此错误的先前问题后,似乎所有人都认为您需要在所有数据源上启用XA。

不,不是全部,除了一个(除了一个例外),如果您的应用服务器支持记录上一个资源(LLR)优化(允许在全局事务中登记一个非XA资源)。

  

为什么上面的代码没有启动完全独立的事务?

因为你不是。在EJB Session Beans后面使用beginTransaction()时,Hibernate将加入JTA事务(有关完整详细信息,请参阅documentation)。所以第一次调用才有效,但第二次调用意味着在当前事务中征募另一个事务资源。由于您的资源都不是XA,因此您会遇到异常。

  

如何强制它启动独立事务而不是分布式事务?

请参阅@ewernli回答。

  

哪种配置可能导致两个应用程序服务器之间的行为差​​异?

不知道。也许其中一个人正在使用至少一个XA数据源。