2009-09-24 7 views
10

J'ai une application qui doit se connecter à plusieurs bases de données. Il s'agit d'une application administrative qui est essentiellement utilisée pour gérer les entrées dans différentes bases de données - nous n'avons pas besoin d'accéder simultanément à plusieurs bases de données et nous n'avons pas besoin d'une sorte de gestion des transactions distribuées.Une bonne façon de configurer les transactions au printemps pour différentes sources de données?

Fondamentalement, une zone de l'application vous permet de créer des gadgets dans la base de données A, et une autre zone de l'application vous permet de configurer des gadgets similaires dans la base de données B.

Nous avons déjà mis en place des transactions et fonctionne parfaitement lorsque vous utilisez un seul la source de données. La configuration ressemble à ceci:

<aop:config> 
    <aop:pointcut id="companyServicePoint" 
      expression="execution(* com.company.service.CompanyService.*(..))" /> 

    <aop:advisor advice-ref="companyServiceTxAdvice" 
     pointcut-ref="companyServicePoint"/> 
</aop:config> 

<tx:advice id="companyServiceTxAdvice" transaction-manager="txManager"> 
    <tx:attributes> 
     <!-- set propogation required on create methods, all others are read-only --> 
     <tx:method name="create*" propagation="REQUIRED"/> 
     <tx:method name="*" read-only="true" /> 
    </tx:attributes> 
</tx:advice> 

<bean id="txManager" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

Ceci définit un point de coupure sur toute exécution de toutes les méthodes au sein CompanyService et associés des conseils de transaction avec le pointcut qui exige que les opérations pour toutes les méthodes dont le nom commence par « créer ». Le conseil de transaction est associé à un TransactionManager lié à dataSource.

Lors de l'ajout d'une deuxième (ou de plusieurs) sources de données, comment puis-je appliquer le même conseil de transaction à d'autres sources de données? Puisque le conseil AOP ne peut être associé qu'à un gestionnaire de transaction, qui ne peut être associé qu'à une seule source de données, dois-je mettre en place un conseil de transaction en double?

Si la configuration I des conseils de transactions en double au même pointcut, ne signifie pas que toute cette invocations de méthodes dans mon interface CompanyService contre, il faudra propogation tous de mes sources de données? Pour rendre ma dernière question un peu plus claire, je vais déclarer plusieurs beans qui implémentent l'interface CompanyService, et chacun de ces beans aura un CompanyDAO séparé pour accéder à leur DataSource. Je crains que cette approche ne signifie que lorsque le bean companyService1 est invoqué, le conseil de transaction sera déclenché sur all companyService beans/dataSources.

Est-ce que je vais dans le mauvais sens?

Mise à jour: je l'ai fait tester la configuration j'ai parlé ci-dessus (attacher deux conseillers à la même pointcut), et invoquer une méthode de chaque cas particulier de la mise en œuvre CompanyService ne en fait créer de nouvelles transactions sur les deux sources de données, comme prévu:

DEBUG company.serviceDataSourceTransactionManager - Creating new transaction with name [com.company.service.CompanyService.createCompany]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 
DEBUG company.serviceDataSourceTransactionManager - Acquired Connection [connection1 string here...] for JDBC transaction 
... 
DEBUG company.serviceDataSourceTransactionManager - Creating new transaction with name [com.company.service.CompanyService.createCompany]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 
DEBUG company.serviceDataSourceTransactionManager - Acquired Connection [connection2 string here...] for JDBC transaction 
... 
DEBUG company.serviceDataSourceTransactionManager - Rolling back JDBC transaction on Connection [connection1 string here...] 
... 
DEBUG company.serviceDataSourceTransactionManager - Rolling back JDBC transaction on Connection [connection2 string here...] 

Cela semble que cela causerait des problèmes sur la route, car soit CompanyService instance ne jamais travailler avec une seule source de données.

Existe-t-il une meilleure façon de configurer ce que je cherche à accomplir?

Répondre

3

Oui, vous avez besoin d'un avis de transaction en double. Notez dans la configuration suivante que l'expression pointcut sélectionne un bean CompanyService spécifique.

<bean id="companyService1" class="com.company.service.CompanyServiceImpl"> 
    <property name="companyDao"> 
    <bean class="com.company.service.CompanyDAO"> 
     <property name="dataSource" ref="dataSource1"/> 
    </bean> 
    </property> 
</bean> 

<aop:config> 
    <aop:pointcut 
     id="companyServicePoint1" 
     expression="bean(companyService1)"/> 
    <aop:advisor 
     advice-ref="companyServiceTxAdvice1" 
     pointcut-ref="companyServicePoint1"/> 
</aop:config> 

<tx:advice id="companyServiceTxAdvice1" transaction-manager="txManager1"> 
    <tx:attributes> 
    <!-- set propogation required on create methods, all others are read-only --> 
    <tx:method name="create*" propagation="REQUIRED"/> 
    <tx:method name="*" read-only="true"/> 
    </tx:attributes> 
</tx:advice> 

<bean 
    id="txManager1" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource1"/> 
</bean> 

Pour configurer un autre bean CompanyService, vous devez dupliquer la même couche standard verbeuse.Une autre façon de démarquer les transactions au printemps utilise TransactionProxyFactoryBean. Il est légèrement moins verbeux car il utilise une définition de bean parent pour configurer les propriétés communes héritées par les beans enfants.

<bean 
    id="baseTransactionProxy" 
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 
    abstract="true"> 
    <property name="transactionAttributes"> 
    <props> 
     <prop key="create*">PROPAGATION_REQUIRED</prop> 
     <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 
    </props> 
    </property> 
</bean> 

<bean id="companyService1" parent="baseTransactionProxy"> 
    <property name="transactionManager" ref="txManager1"/> 
    <property name="target"> 
    <bean class="com.company.service.CompanyServiceImpl"> 
     <property name="companyDao"> 
     <bean class="com.company.service.CompanyDAO"> 
      <property name="dataSource" ref="dataSource1"/> 
     </bean> 
     </property> 
    </bean> 
    </property> 
</bean> 

<bean 
    id="txManager1" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
    <property name="dataSource" ref="dataSource1"/> 
</bean> 
+0

Merci, cela fonctionne bien - une seule transaction est créée lorsque l'une ou l'autre instance du bean est invoquée. Pas aussi élégant d'une solution que de déclarer le pointcut sur l'interface, mais c'est ce que demande mon cas d'utilisation ... –

Questions connexes