Ошибка «Локальная транзакция уже имеет 1 ресурс не-XA: невозможно добавить больше ресурсов» - PullRequest
4 голосов
/ 21 мая 2010

После прочтения предыдущих вопросов об этой ошибке кажется, что все они пришли к выводу, что вам нужно включить XA для всех источников данных. Но:

  1. Что делать, если я не хочу распределенную сделка? Что я буду делать, если захочу начать транзакции на двух разных базы данных в то же время, но зафиксировать транзакцию в одной базе данных и откат транзакции на другой?
  2. Мне интересно, как мой код фактически инициировал распределенный сделка. Мне кажется, что я начиная совершенно отдельно транзакции на каждом из базы данных.

Информация о приложении:

Приложение представляет собой EJB-компонент, работающий на сервере приложений Sun Java 9.1

Я использую что-то вроде следующего весеннего контекста, чтобы настроить фабрики сеансов гибернации:

<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. Какая конфигурация может вызвать разницу в поведение между двумя приложениями серверы?

Спасибо.

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 ]

5 голосов
/ 21 мая 2010

1 Почему вышеуказанный код не запускает полностью независимые транзакции?

Приложение. Сервер управляет транзакцией за вас, которая при необходимости может быть распределенной транзакцией. Зачисляет всех участников автоматически. Когда есть только один участник, вы не замечаете никакой разницы с простой транзакцией JDBC, но если их несколько, распределенная транзакция действительно необходима, поэтому возникает ошибка.

2 Как заставить его запускать независимые транзакции, а не распределенная транзакция?

Вы можете настроить источник данных на , будь то XA или локальный . Поведение транзакций в Spring / Hibernate также можно настроить на использование обычных транзакций JDBC или делегирование управления транзакциями диспетчеру распределенных транзакций JTA.

Я предлагаю вам переключить источник данных на не-XA и попытаться настроить Spring / Hibernate для использования транзакций JDBC. Вы должны найти соответствующую информацию в документации , здесь, как я подозреваю, есть строка для изменения:

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

По сути, это означает, что вы не используете приложение. Диспетчер распределенных транзакций на сервере.

3 Какая конфигурация может вызвать разницу в поведении между два сервера приложений?

Если у вас действительно одно и то же приложение и конфигурация, это означает, что в одном случае только один участник зачисляется на дистанцию. транзакции, пока их два во 2-м случае. Один участник обычно соответствует одному физическому соединению с базой данных. Может ли быть так, что в одном случае вы используете две схемы в двух разных базах данных, а во втором - две схемы в физической базе данных ? Более вероятным объяснением будет то, что источник данных был настроен по-разному в двух приложениях. сервер.

PS: если вы используете распределенные транзакции JTA, вы должны использовать UserTransaction.{begin,commit,rollback}, а не их эквивалент в Session.

1 голос
/ 21 мая 2010

После прочтения предыдущих вопросов об этой ошибке кажется, что все они пришли к выводу, что вам нужно включить XA для всех источников данных.

Нет, не все, все, кромеодин (как говорит исключение), если ваш сервер приложений поддерживает оптимизацию «Logging Last Resource (LLR)» (которая позволяет включить один ресурс, не относящийся к XA, в глобальную транзакцию).

Почему неПриведенный выше код запускает полностью независимые транзакции?

Потому что это не так.При использовании beginTransaction() за сессионными компонентами EJB Hibernate присоединится к транзакции JTA (подробные сведения см. В документации 1013 *).Таким образом, первый вызов просто работает, но второй вызов означает привлечение другого транзакционного ресурса в текущей транзакции.И поскольку ни один из ваших ресурсов не является XA, вы получаете исключение.

Как заставить его запускать независимые транзакции, а не распределенную транзакцию?

См. @ ewernli ответ.

Какая конфигурация может вызвать различия в поведении между двумя серверами приложений?

Не знаю.Возможно, один из них использует хотя бы один источник данных XA.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...