2009-09-24 4 views
10

Ich habe eine Anwendung, die eine Verbindung zu mehreren Datenbanken herstellen muss. Dies ist eine administrative Anwendung, die im Grunde verwendet wird, um Einträge in verschiedenen Datenbanken zu verwalten - wir müssen nicht auf mehrere Datenbanken gleichzeitig zugreifen, noch benötigen wir irgendeine Art von verteilter Transaktionsverwaltung.Richtige Methode zum Einrichten von Transaktionen im Frühling für verschiedene Datenquellen?

Grundsätzlich ein Bereich der Anwendung können Sie Geräte in der Datenbank A zu erstellen, und ein weiterer Bereich der Anwendung können Sie ähnliche Geräte in der Datenbank B. konfigurieren

Wir haben bereits Transaktionen einzurichten und perfekt funktioniert, wenn nur einer mit Datenquelle. Die Konfiguration sieht so aus:

<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> 

Dies setzt einen pointcut auf jeder Ausführung von Methoden innerhalb CompanyService und Transaktionsberatung mit dem pointcut assoziiert, die Transaktionen für alle Methoden, deren Name mit „create“ erfordert. Der Transaktionshinweis ist einem TransactionManager zugeordnet, der an die dataSource gebunden ist.

Wenn ich eine zweite (oder mehrere) Datenquellen hinzufüge, wie kann ich den gleichen Transaktionshinweis auf andere Datenquellen anwenden? Da der AOP-Hinweis nur einem transactionManager zugeordnet werden kann, der nur einer dataSource zugeordnet werden kann, muss ich einen doppelten Transaktionshinweis einrichten?

Wenn ich Setup doppelte Transaktionsberatung zum gleichen pointcut, bedeutet dies nicht, dass alle Aufrufe von Methoden in meiner CompanyService Schnittstelle propogation gegen all meine datasources benötigen?

Um meine letzte Frage ein wenig klarer zu machen, werde ich mehrere Beans deklariert haben, die die CompanyService Schnittstelle implementieren, und jede dieser Beans wird eine separate CompanyDAO haben, um auf ihre individuelle DataSource zuzugreifen. Ich befürchte, dass dieser Ansatz dazu führt, dass beim Aufruf der Bean companyService1 der Transaktionshinweis unter all firmaService-Beans/dataSources ausgelöst wird.

Gehe ich in die falsche Richtung?

Update: Ich habe tatsächlich die Konfiguration, die ich oben gesprochen testeten (Anbringen von zwei Berater der gleichen pointcut) und Aufrufen einer beliebigen Methode auf entweder einzelne Instanz der CompanyService Umsetzung ist in der Tat auf beiden neuen Transaktionen erstellen Datasources wie erwartet:

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...] 

Dies scheint es Probleme auf dem Weg führen würde, da entweder CompanyService Instanz immer nur mit einem einzigen Datasource arbeitet.

Gibt es einen besseren Weg zu konfigurieren, was ich erreichen möchte?

Antwort

3

Ja, Sie müssen eine doppelte Transaktionsberatung. Beachten Sie in der folgenden Konfiguration, dass der Pointcut-Ausdruck eine bestimmte CompanyService-Bean auswählt.

<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> 

Um eine andere CompanyService-Bean zu konfigurieren, müssen Sie die gleiche ausführliche Boilerplate duplizieren.Eine andere Möglichkeit, Transaktionen im Frühling abzugrenzen, ist TransactionProxyFactoryBean. Es ist etwas weniger ausführlich, da es eine Definition der übergeordneten Bean verwendet, um allgemeine Eigenschaften zu konfigurieren, die von untergeordneten Beans geerbt werden.

<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

Danke, das funktioniert gut - nur eine einzige Transaktion wird erstellt, wenn eine Bean-Instanz aufgerufen wird. Nicht so elegant wie der Pointcut auf der Schnittstelle zu deklarieren, aber das ist es, was mein Anwendungsfall erfordert ... –

Verwandte Themen