2009-09-24 15 views
10

Tengo una aplicación que necesita conectarse a múltiples bases de datos. Esta es una aplicación administrativa que básicamente se usa para administrar entradas en diferentes bases de datos: no necesitamos acceder a múltiples bases de datos simultáneamente ni necesitamos ningún tipo de administración de transacciones distribuidas.¿La forma correcta de configurar las transacciones en Spring para diferentes orígenes de datos?

Básicamente un área de la aplicación le permite crear aparatos en la base de datos A, y otra área de la aplicación le permitirá configurar aparatos similares en la base de datos B.

Ya hemos establecido las transacciones y funciona perfectamente cuando se utiliza un solo fuente de datos. La configuración se ve así:

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

Esto establece un punto de corte en cualquier ejecución de cualquiera de los procedimientos dentro de CompanyService y asociados consejos transacción con el punto de corte que requiere que las transacciones de cualquier método cuyo nombre empieza por "crear". El aviso de transacción está asociado con un TransactionManager que está vinculado a la fuente de datos.

Al agregar un segundo (o más) datasources, ¿cómo puedo aplicar el mismo aviso de transacción a otras fuentes de datos? Dado que el asesoramiento de AOP solo puede asociarse con un transactionManager, que solo puede asociarse con un dataSource, ¿necesito configurar un aviso de transacción duplicado?

Si I fijó el asesoramiento de transacciones duplicado en el mismo punto de corte, no significa esto que cualquier invocación de métodos en mi interfaz CompanyService requerirán propagación contra toda de mis dataSources?

Para hacer mi última pregunta un poco más clara, voy a tener varios beans declarados que implementan la interfaz CompanyService, y cada uno de estos beans tendrá un CompanyDAO por separado para acceder a su DataSource individual. Me temo que este enfoque significará que cuando se invoca el bean companyService1, se activará el aviso de transacción en all companyService beans/dataSources.

¿Voy por esto de la manera incorrecta?

Actualización: De hecho, he probado a cabo la configuración que hablé anteriormente (adjuntando dos asesores del mismo punto de corte), e invocando cualquier método a cada caso concreto de aplicación CompanyService no, de hecho, crear nuevas transacciones tanto dataSources, como se esperaba:

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

esto parece que podría causar problemas en el camino, ya sea CompanyService instancia es solamente siempre trabajando con una sola fuente de datos.

¿Hay una mejor manera de configurar lo que intento lograr?

Respuesta

3

Sí, se necesita un asesoramiento de transacciones duplicado. Observe en la siguiente configuración que la expresión de corte puntual selecciona un bean CompanyService específico.

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

Para configurar otro bean CompanyService, debe duplicar el mismo texto detallado.Otra forma de demarcar transacciones en Spring usa TransactionProxyFactoryBean. Es un poco menos detallado porque usa una definición de bean padre para configurar las propiedades comunes heredadas por beans hijos.

<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

Gracias, esto funciona bien: solo se crea una transacción cuando se invoca cualquiera de las instancias de bean. No es tan elegante de una solución como declarar el corte de punto en la interfaz, pero esto es lo que mi caso de uso exige ... –

Cuestiones relacionadas