【问题标题】:"Local transaction already has 1 non-XA Resource: cannot add more resources" error“本地事务已经有 1 个非 XA 资源:无法添加更多资源”错误
【发布时间】:2011-02-22 03:27:33
【问题描述】:

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

  1. 如果我不想要分布式怎么办? 交易?如果我想我会怎么做 在两个不同的地方开始交易 同时数据库,但 在一个数据库上提交事务 并回滚事务 另一个?
  2. 我想知道我的代码如何 实际上发起了一个分布式 交易。在我看来,我是 开始完全分开 每一笔交易 数据库。

申请信息:

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

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

<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. 什么配置可能导致差异 两个应用程序之间的行为 服务器?

谢谢。

附:堆栈跟踪是:

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

【问题讨论】:

  • 连接池设置中的“非事务性连接”复选框起到了作用。奇怪的是,它在两个应用服务器中都未选中,但显然其中一个正在返回非事务连接。

标签: java hibernate jdbc ejb


【解决方案1】:

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

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

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

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

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

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

这本质上应该意味着您没有使用该应用程序。服务器分布式事务管理器。

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

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

PS:如果你使用 JTA 分布式事务,你应该使用UserTransaction.{begin,commit,rollback} 而不是Session 上的等价物。

【讨论】:

  • 实际上,我很惊讶容器允许 OP 在托管环境中调用 session.beginTransaction,但如果您这样做,Hibernate 似乎会自动加入 JTA 环境中的当前 JTA 事务(适用于 CMT 甚至 BMT,如果需要,Hibernate 将启动 UserTransation)。见redhat.com/docs/en-US/JBoss_Hibernate/3.2.4.sp01.cp03/html/…
【解决方案2】:

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

如果您的应用程序服务器支持 Logging Last Resource (LLR) 优化(允许在全局事务中登记一个非 XA 资源),则不,不是全部,除了一个(正如例外所说)。

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

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

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

请参阅@ewernli 答案。

什么配置会导致两个应用服务器之间的行为不同?

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

【讨论】:

  • “我的建议是将您的资源之一配置为 XA 资源”如果我这样做,我是否能够回滚一个事务并提交另一个事务?
  • “不,不是全部,除了一个” - 是的,感谢您指出这一点
  • FWIW、LLR(又名 LPS / WAS 中的最后参与者支持)引入了启发式风险的风险:如果 1PC 资源没有响应(超时、丢失连接等),则没有办法了解 XA 资源分支的结果应该是什么。
  • @bkail:感谢分享。
猜你喜欢
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
  • 1970-01-01
  • 2013-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多