web-dev-qa-db-fra.com

Comment configurer la gestion des transactions pour travailler avec 2 bases de données différentes au printemps?

J'ai 2 bases de données (MySql et HSQLDB). J'ai configuré 2 sources de données et 2 beans EntityManagerFactory. Je peux également configurer 2 beans JpaTransactionManager correspondants.

Mais je ne sais pas comment spécifier lequel doit être utilisé pour gérer les transactions pour une classe de service concrète. Je veux utiliser @Transactional annotation à cet effet, mais je ne peux en fait spécifier qu'un seul des txManagers:

<tx:annotation-driven transaction-manager="manager"/>

Quelle est la sortie de cette situation?

35
Roman

javadoc pour JpaTransactionManager a quelques conseils à ce sujet:

Ce gestionnaire de transactions convient aux applications qui utilisent une seule entité JPA EntityManagerFactory pour l'accès aux données transactionnelles. JTA (généralement via JtaTransactionManager) est nécessaire pour accéder à plusieurs ressources transactionnelles au sein d'une même transaction. Notez que vous devez configurer votre fournisseur JPA en conséquence afin de le faire participer aux transactions JTA.

En d'autres termes, si vous vous trouvez avec plusieurs gestionnaires d'entités, avec les gestionnaires tx correspondants, alors vous devriez envisager d'utiliser un seul JtaTransactionManager à la place. Les gestionnaires d'entités devraient pouvoir participer aux transactions JTA, ce qui vous donnera une transactionnalité complète entre les deux gestionnaires d'entités, sans avoir à vous soucier du gestionnaire d'entités dans lequel vous vous trouvez à un moment donné.

Bien sûr, JtaTransactionManager nécessite un serveur d'applications prenant en charge JTA complet, plutôt qu'un moteur de servlet Vanilla comme Tomcat.

18
skaffman

Déclarez votre <tx:annotation-driven> sans l'attribut transaction-manager, déclarez les qualificatifs pour les gestionnaires de transactions comme ceci:

<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <qualifier value="txManager1"/>
</bean>

Utilisez ce qualificatif dans @ Transactional comme valeur pour sélectionner l'un des gestionnaires de transactions:

@Transactional("txManager1")

ou, avec plus de propriétés:

@Transactional(value = "txManager1", readOnly = true)   
19
axtavt

Depuis son après une longue période depuis les bonnes réponses.

Skaffman peut être correct en termes d'utilisation de JpaTransactionManager pour plusieurs bases de données.

Mais il existe une solution de travail pour utiliser 2 bases de données différentes avec 2 JpaTransactionManager différents.

  @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 doit être utilisé pour spécifier ceux pour lesquels vous ne spécifiez pas de nom de qualificateur dans @Transactional

12
raksja

Vous devez spécifier deux gestionnaires de transactions pour cela dans application-context.xml comme ci-dessous:

<tx:annotation-driven transaction-manager="manager1"/>
<tx:annotation-driven transaction-manager="manager2"/>

L'attribut @Transactional utilisera désormais son gestionnaire de transactions approprié.

6
Mital Pritmani