2014-04-13 30 views
12

Tôi có ba DataSource (JDBC) được định nghĩa trong tệp ngữ cảnh ứng dụng Junit. Hai trong số họ cần được quản lý giao dịch; Tôi không phải kết nối bất kỳ phương pháp nào khi sử dụng hai nguồn dữ liệu này (chúng hoàn toàn độc lập với nhau).Nhiều nguồn dữ liệu với nhiều người quản lý giao dịch trong mùa xuân

Tôi không gặp sự cố khi tôi sử dụng một người quản lý giao dịch duy nhất cho dataSource2, mặc dù dataSource3 đã được sử dụng nhưng không được quản lý theo các phương pháp tương ứng. Tuy nhiên, khi cần quản lý các phương thức từ các lớp DAO khác nhau chỉ sử dụng dataSource3, tôi đã thêm giao dịch thứ hai - txManager2. Các tập tin bối cảnh chứa thông tin sau:

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

Kể từ khi nhiều nhà quản lý giao dịch đang được xác định, tôi có trình độ chúng với các giá trị của riêng mình. Như bạn có thể thấy, dataSource3 đang được tiêm sử dụng một phương pháp setter:

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() { } 
} 

Tuy nhiên, khi chạy các đơn vị kiểm tra Junit, tôi nhận được như sau:

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) 

Bất kỳ ý tưởng nơi khởi nguồn của vấn đề là?

Cập nhật

Dựa trên câu trả lời được chấp nhận, các thay đổi sau đã được thực hiện để có được những chức năng dự định:

<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") nên đã được sửa chữa (typo trên một phần của tôi):

// Read only from datasource 
    @Autowired 
    @Qualifier("dataSource1") 
    public void setDataSource1(DataSource ds) { 
     template = new NamedParameterJdbcTemplate(ds); 
    } 

Trả lời

9

Có một số sự cố với cấu hình của bạn:

<property name="dataSource2" ref="dataSource2"/> 
<property name="dataSource3" ref="dataSource3"/> 

tên bean khác nhau, nhưng tên thuộc tính thì không. Bạn nên thay đổi điều này thành:

<property name="dataSource" ref="dataSource2"/> 
<property name="dataSource" ref="dataSource3"/> 

Ví dụ: trong các thuộc tính setter cho đậu txManager1 và txManager2 tương ứng.

Thứ hai: @Qualifier("dataSource2")@Qualifier("dataSource3") là sai vì bạn đủ điều kiện cho các nhà quản lý TX đậu chứ không phải bean nguồn dữ liệu.

Thay vào đó, bạn có thể sử dụng @Resource("dataSource2")@Resource("dataSource3") hoặc đủ điều kiện cho các hạt nguồn dữ liệu.

Thứ ba: @Qualifier("dataSource"). Lưu ý rằng nó không phải là khiếu nại hoặc với một vòng loại và tên của một bean (lưu ý: đó là dataSource1)

Điều cuối cùng, bạn đã xác định tx:annotation-driven. Dự kiến ​​người quản lý giao dịch có tên bean là transactionManager. Bạn đã không đưa ra định nghĩa bean của nó là tốt, vì vậy điều này sẽ thất bại hoặc.

+0

Tên thuộc tính là vấn đề và tôi đã quên bao gồm giao dịch đầu tiên trong 'tx: chú thích định hướng'. Sai lầm vòng loại 'dataSource' là một lỗi đánh máy (tôi để nó trong câu hỏi để câu trả lời được cung cấp sẽ không bị lỗi cho người đọc trong tương lai). – Malvon

+0

Làm việc cho tôi. cảm ơn các bạn. – Shashank

+0

Giải thích cổ điển :) –

Các vấn đề liên quan