[英]Multiple DataSources with Multiple Transaction Managers in Spring
I have three DataSource
's (JDBC) defined in the Junit application context file. 我在Junit应用程序上下文文件中定义了三个
DataSource
(JDBC)。 Two of them need to be transactionally managed; 其中两个需要进行交易管理; I do not have to chain any of the methods when using these two data sources (they are entirely independent of each other).
使用这两个数据源时,我不必链接任何方法(它们完全相互独立)。
I did not have a problem when I used a single transaction manager for dataSource2
, even though dataSource3
was being utilized but not managed in the corresponding methods. 当我使用单个事务管理器进行
dataSource2
,我没有遇到任何问题,即使dataSource3
正在被使用但未在相应的方法中进行管理。 Nonetheless, upon needing to also manage methods from various DAO classes that solely use dataSource3
, I added the second transaction -- txManager2
. 尽管如此,在需要管理来自仅使用
dataSource3
各种DAO类的方法时,我添加了第二个事务txManager2
。 The context file contains the following: 上下文文件包含以下内容:
<context:component-scan base-package="my.pkg" />
<bean id="dataSource1"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@host1:1521:dbsid1" />
<property name="username" value="username1" />
<property name="password" value="password1" />
</bean>
<bean id="dataSource2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@host2:1521:dbsid2" />
<property name="username" value="username2" />
<property name="password" value="password2" />
</bean>
<bean id="dataSource3"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@host3:1521:dbsid3" />
<property name="username" value="username3" />
<property name="password" value="password3" />
</bean>
<tx:annotation-driven/>
<bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<qualifier value="txManager1"/>
<property name="dataSource2" ref="dataSource2"/>
</bean>
<bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<qualifier value="txManager2"/>
<property name="dataSource3" ref="dataSource3"/>
</bean>
Since multiple transaction managers are being defined, I qualified them with their own values. 由于正在定义多个事务管理器,因此我使用自己的值对它们进行了限定 。 As you can see,
dataSource3
is being injected using a setter method: 如您所见,使用setter方法注入
dataSource3
:
package my.pkg;
@Component
public class MyDAO {
private DataSource dataSource3;
// Read only from datasource
@Autowired
@Qualifier("dataSource")
public void setDataSource(DataSource ds) {
template = new NamedParameterJdbcTemplate(ds);
}
// Performs reads/updates/inserts from datasource2
@Autowired
@Qualifier("dataSource2")
public void setDataSource2(DataSource ds) {
iTemplate = new NamedParameterJdbcTemplate(ds);
}
// Performs reads/updates/inserts from datasource3
@Autowired
@Qualifier("dataSource3")
public void setDataSource3(DataSource ds) {
dataSource3 = ds;
uTemplate = new NamedParameterJdbcTemplate(ds);
}
@Transactional("txManager1")
public String insertProcs() { }
@Transactional("txManager2")
public String updateProcs() { }
}
However, upon running the Junit unit test , I get the following: 但是,在运行Junit单元测试时 ,我得到以下结果:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:308)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'txManager2' defined in class path resource [test-context.xml]:
Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'dataSource3' of bean class
[org.springframework.jdbc.datasource.DataSourceTransactionManager]: Bean property 'dataSource3' is not writable or has an invalid setter method. Does the parameter
type of the setter match the return type of the getter?
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1363)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1085)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:280)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:304)
... 24 more
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'dataSource3' of bean class
[org.springframework.jdbc.datasource.DataSourceTransactionManager]: Bean property 'dataSource3' is not writable or has an invalid setter method. Does the parameter
type of the setter match the return type of the getter?
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1052)
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:921)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:76)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:58)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360)
Any idea where the source of the problem is? 知道问题的根源在哪里?
Based on the answer accepted, the following changes were made to get the intended functionality: 根据接受的答案,进行了以下更改以获得预期的功能:
<tx:annotation-driven transaction-manager="txManager1"/>
<bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<qualifier value="txManager1"/>
<property name="dataSource" ref="dataSource2"/>
</bean>
<bean id="txManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<qualifier value="txManager2"/>
<property name="dataSource" ref="dataSource3"/>
</bean>
@Qualifier("dataSource")
should have been corrected (typo on my part): 应该更正
@Qualifier("dataSource")
(我的错字):
// Read only from datasource
@Autowired
@Qualifier("dataSource1")
public void setDataSource1(DataSource ds) {
template = new NamedParameterJdbcTemplate(ds);
}
There are few problems with your configuration: 您的配置几乎没有问题:
<property name="dataSource2" ref="dataSource2"/>
<property name="dataSource3" ref="dataSource3"/>
The bean names are different, but property names are not. bean名称不同,但属性名称不同。 You should change this to:
你应该改为:
<property name="dataSource" ref="dataSource2"/>
<property name="dataSource" ref="dataSource3"/>
Eg: in setter properties for txManager1 and txManager2 beans respectively. 例如:分别在txManager1和txManager2 bean的setter属性中。
Second: @Qualifier("dataSource2")
and @Qualifier("dataSource3")
are wrong since your are qualifying the TX managers beans, and not the data-source beans. 第二:
@Qualifier("dataSource2")
和@Qualifier("dataSource3")
是错误的,因为您正在验证TX经理bean,而不是数据源bean。
You can use @Resource("dataSource2")
and @Resource("dataSource3")
instead, or qualify the data-source beans as well. 您可以使用
@Resource("dataSource2")
和@Resource("dataSource3")
代替,也可以使用数据源bean。
Third: @Qualifier("dataSource")
. 第三:
@Qualifier("dataSource")
。 Notice it's not complaint either with a qualifier and a bean's name (note: it's dataSource1 ) 请注意,使用限定符和bean的名称并不是抱怨(注意:它是dataSource1 )
As a last thing, you have defined tx:annotation-driven
. 最后,你定义了
tx:annotation-driven
。 It expects a transaction manager whose bean name is transactionManager . 它需要一个bean名称为transactionManager的事务管理器。 You have failed to give it's bean definition as well, so this will fail either.
你也没有给它的bean定义,所以这也会失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.