我有一个需要连接到多个数据库的应用程序。这是一个管理应用程序,主要用于管理不同数据库中的条目 - 我们不需要同时访问多个数据库,也不需要任何类型的分布式事务管理。
基本上,应用程序的一个区域允许您在数据库A中创建小工具,而应用程序的另一个区域允许您在数据库B中配置类似的小工具。
只使用一个数据源时,我们已经设置了事务并且工作正常。配置如下:
<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>
这为CompanyService
中的任何方法的任何执行设置切入点,并将事务通知与切入点相关联,切入点需要对名称以“create”开头的任何方法进行事务处理。事务通知与TransactionManager相关联,该事务管理器与dataSource相关联。
添加第二个(或更多)数据源时,如何将相同的事务建议应用于其他数据源?由于AOP建议只能与一个只能与一个dataSource关联的transactionManager关联,我是否需要设置重复的事务建议?
如果我将重复的事务建议设置为相同的切入点,这是否意味着我的CompanyService
接口中的任何方法调用都需要针对所有我的dataSources进行传播?
为了使我的上一个问题更清楚一点,我将声明多个bean实现CompanyService
接口,并且每个bean都有一个单独的CompanyDAO
来访问它们各自的DataSource。我担心这种方法意味着当调用companyService1
bean时,将在all
companyService beans / dataSources上触发事务建议。
我是以错误的方式解决这个问题吗?
更新:我实际测试了我上面谈到的配置(将两个顾问程序连接到同一个切入点),并在CompanyService
实现的单个实例上调用任何方法实际上确实在两个dataSource上创建了新的事务,正如预期的那样:
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...]
这似乎会导致问题,因为CompanyService
实例只能使用单个DataSource。
有没有更好的方法来配置我想要完成的任务?
答案 0 :(得分:3)
是的,您需要重复的交易建议。请注意,在以下配置中,切入点表达式选择特定的CompanyService bean。
<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>
要配置另一个CompanyService bean,您需要复制相同的详细样板文件。在Spring中划分事务的另一种方法是使用TransactionProxyFactoryBean
。它略微冗长,因为它使用父bean定义来配置子bean继承的公共属性。
<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>
答案 1 :(得分:0)
您是否尝试过使用JtaTransactionManager?