Как настроить управление транзакциями для работы с двумя разными db в Spring?
У меня есть 2 базы данных (MySql и HSQLDB). Я настроил 2 источника данных и 2 EntityManagerFactory beans. Я также могу настроить 2 соответствующих JpaTransactionManager beans.
Но я не знаю, как указать, какие из них должны использоваться для управления транзакциями для конкретного класса обслуживания. Я хочу использовать аннотацию @Transactional
для этой цели, но на самом деле могу указать только один из txManagers:
<tx:annotation-driven transaction-manager="manager"/>
Каков выход из этой ситуации?
Ответы
Ответ 1
javadoc для JpaTransactionManager имеет несколько советов по этому поводу:
Этот менеджер транзакций подходит для приложений, которые используют один JPA EntityManagerFactory для доступ к транзакционным данным. JTA (обычно через JtaTransactionManager) необходимо для доступа к нескольким транзакционным ресурсов в рамках одной транзакции. Обратите внимание, что вам необходимо настроить JPA, соответственно, чтобы принять участие в JTA сделки.
Другими словами, если вы обнаружите себя с несколькими менеджерами сущностей с соответствующими менеджерами tx, вам следует рассмотреть возможность использования одного JtaTransactionManager
вместо. Менеджеры сущностей должны иметь возможность участвовать в транзакциях JTA, и это даст вам полную транзакцию для обоих менеджеров сущностей, не опасаясь, чтобы беспокоиться о том, какой менеджер сущностей вы находитесь в любой момент.
Конечно, JtaTransactionManager
требует полного сервера приложений, поддерживающего JTA, а не движка серфинга ванили, такого как Tomcat.
Ответ 2
Объявите свой <tx:annotation-driven>
без атрибута transaction-manager, объявите квалификаторы для менеджеров транзакций следующим образом:
<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<qualifier value="txManager1"/>
</bean>
Используйте этот определитель в @Transactional в качестве значения для выбора одного из менеджеров транзакций:
@Transactional("txManager1")
или, с большим количеством свойств:
@Transactional(value = "txManager1", readOnly = true)
Ответ 3
С тех пор как после долгого времени с правильных ответов.
Скаффман может быть правильным с точки зрения удобства использования JpaTransactionManager для нескольких баз данных.
Но есть рабочее решение для использования 2 разных баз данных с двумя разными JpaTransactionManager.
@Bean(name = "db2TransactionManager")
public PlatformTransactionManager transactionManager2() throws NamingException {
JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
return txManager;
}
@Bean
@Primary
public PlatformTransactionManager transactionManager() throws Exception {
JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
txManager.setNestedTransactionAllowed(true);
return txManager;
}
@Primary
следует использовать для указания тех, где вы не указываете имя квалификатора в @Transactional
Ответ 4
Вы должны указать два менеджера транзакций для этого в application-context.xml, как показано ниже:
<tx:annotation-driven transaction-manager="manager1"/>
<tx:annotation-driven transaction-manager="manager2"/>
Атрибут @Transactional теперь будет использовать соответствующий менеджер транзакций.