J'utilise l'annotation @Configuration
pour la configuration du ressort au lieu du fichier xml. Je configure 2 sources de données avec différentes fabriques de sessions et différents gestionnaires de transactions. Je suis coincé avec un problème ici pour l'annotation @EnableTransactionManagement
. J'ai lu dans sa documentation que,
@EnableTransactionManagement
est plus flexible; il va retomber à un recherche par type pour tout beanPlatformTransactionManager
dans le fichier récipient. Ainsi, le nom peut être "txManager", "transactionManager" ou "tm": ça n'a pas d'importance.
Cela signifie que quel que soit le nom que je donne à method, il cherchera toujours la méthode qui retourne un objet PlatformTransactionManager
tant que je dispose de 2 gestionnaires de transaction. Maintenant, le problème est que, lorsque je teste cette classe, cela me donne une erreur:
org.springframework.beans.factory.NoSuchBeanDefinitionException
: aucun bean unique de type [org.springframework.transaction.PlatformTransactionManager
] n'est défini: bean simple attendu mais trouvé 2
J'ai même essayé d'avoir 2 classes de configuration différentes mais en vain. Dans la configuration XML, ce n'était pas le cas. J'ai enregistré mes deux gestionnaires de transaction avec deux balises <tx:annotation-driven transaction-manager="" />
et cela a bien fonctionné. Mais pas capable de faire la même chose ici avec des annotations.
Que dois-je faire si je veux configurer 2 sources de données avec 2 gestionnaires de transactions différents dans la classe de configuration annotée Spring?
Dans votre classe de configuration, utilisez l'annotation @EnableTransactionManagement
.
Définissez un gestionnaire de transactions dans cette classe comme suit:
@Bean(name="txName")
public HibernateTransactionManager txName() throws IOException{
HibernateTransactionManager txName= new HibernateTransactionManager();
txName.setSessionFactory(...);
txName.setDataSource(...);
return txName;
}
Dans votre classe/méthode qui exécute le (s) travail (s) transactionnel (s), annotez comme suit:
@Transactional("txName")
ou
@Transactional(value = "txName")
C’est ainsi que vous associeriez un gestionnaire de transactions qualifié par nom à l’endroit où vous en avez besoin. Vous pouvez maintenant avoir autant de gestionnaires de transactions que vous le souhaitez et l'utiliser en conséquence, où que vous soyez.
Juste au cas où quelqu'un rencontrerait ce problème, j'ai trouvé une solution:
@Configuration
@EnableTransactionManagement
@DependsOn("myTxManager")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements TransactionManagementConfigurer {
@Autowired
private PlatformTransactionManager myTxManager;
...
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return this.myTxManager;
}
De cette manière, vous pouvez utiliser un txManager spécifique défini dans une configuration XML.
Si vous voulez définir le txManager utilisé au niveau service, vous devez supprimer l'annotation @EnableTransactionManagement
de la classe @Configuration
et spécifier le txManager dans les annotations @Transactional
, par exemple.
@Service
@Transactional(value="myTxManager", readOnly = true)
public class MyServiceImpl implements MyService { ... }
Depuis le Java doc
Pour ceux qui souhaitent établir une relation plus directe entre
@EnableTransactionManagement
et le bean exact du gestionnaire de transactions à utiliser, le Une interface de rappelTransactionManagementConfigurer
peut être implémentée - notez le implémente la clause et la méthode@Override
- annotée ci-dessous:
Votre classe @Configuration
doit implémenter l'interface TransactionManagementConfigurer
- implémentez la annotationDrivenTransactionManager
qui retournera la référence à la transactionManager
qui devrait être utilisée.
Je ne sais pas pourquoi vous utilisez deux gestionnaires de transactions. Vous pouvez envisager d'utiliser le même TransactionManager pour plusieurs sources de données via AbstractRoutingDataSource. Se il vous plaît se référer
http://blog.springsource.org/2007/01/23/dynamic-datasource-routing/
pour un échantillon sur son utilisation.
Certaines des autres réponses impliquent que l'utilisation de deux gestionnaires de transactions est en quelque sorte une erreur. Cependant, la configuration XML de Spring permet d'utiliser plusieurs gestionnaires de transactions, comme indiqué dans la documentation en ligne (ci-dessous). Malheureusement, il ne semble pas y avoir de moyen de faire en sorte que l'annotation @EnableTransactionManagement
fonctionne de la même manière. En conséquence, j'utilise simplement une annotation @ImportResource
pour charger un fichier XML incluant la ligne <tx:annotation-driven/>
. Cela vous permet d'obtenir une configuration Java pour la plupart des choses, tout en utilisant toujours @Transactional
avec un qualificatif facultatif du gestionnaire de transactions.
http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/transaction.html
La plupart des applications Spring n'ont besoin que d'un seul gestionnaire de transactions, mais il peut arriver que vous souhaitiez plusieurs gestionnaires de transactions indépendants dans une même application. L'attribut value de l'annotation
@Transactional
peut être utilisé pour spécifier éventuellement l'identité de laPlatformTransactionManager
à utiliser. Il peut s'agir du nom du bean ou de la valeur de qualificateur du bean du gestionnaire de transactions. Par exemple, en utilisant la notation de qualificatif, le code Java suivant
Essayez d'utiliser chaîné TransactionalManager
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
public class ChainedDBConfig {
@Bean("chainedTransactionManager")
public PlatformTransactionManager transactionManager(
@Qualifier("database1TransactionManager") final PlatformTransactionManager db1PlatformTransactionManager,
@Qualifier("database2TransactionManager") final PlatformTransactionManager db2PlatformTransactionManager) {
return new ChainedTransactionManager(db1PlatformTransactionManager, db2PlatformTransactionManager);
}
}
Et placez l'annotation suivante sur votre classe de service:
@Transactional(transactionManager = "chainedTransactionManager")
public class AggregateMessagesJobIntegrationTest {
...
}
Vous pouvez également l'utiliser dans les tests d'intégration:
@RunWith(SpringRunner.class)
@Transactional(transactionManager = "chainedRawAndAggregatedTransactionManager")
@Rollback
public class ExampleIntegrationTest extends AbstractIntegrationTest {
....
}
et il effectuera une restauration pour les deux gestionnaires de transactions de base de données.