Как настроить нескольких менеджеров транзакций с весны + д. Банкрофт + с JUnit
В двух словах
Мое Java-приложение командной строки копирует данные из одного источника данных в другой без использования XA. Я настроил два отдельных источника данных и хотел бы получить тест JUnit, который может откатывать данные на обоих источниках данных. Я использую DBUnit для загрузки данных в базу данных" source", но не могу заставить ее откатиться. Я могу заставить" целевой " источник данных откатиться.
Мой Код
Учитывая эту конфигурацию...
<tx:annotation-driven />
<!-- note the default transactionManager name on this one -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceA" />
</bean>
<bean id="transactionManagerTarget" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceB" />
</bean>
И это код...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:resources/spring-context.xml",
"classpath:resources/spring-db.xml"})
@Transactional
@TransactionConfiguration(transactionManager = "transactionManagerTarget", defaultRollback = true)
public class MyIntegrationTest {
@Autowired
private MyService service;
@Autowired
@Qualifier("dataSourceA")
private DataSource dataSourceA;
private IDataSet loadedDataSet;
/**
* Required by DbUnit
*/
@Before
public void setUp() throws Exception {
SybaseInsertIdentityOperation.TRUNCATE_TABLE.execute(getConnection(), getDataSet());
SybaseInsertIdentityOperation.INSERT.execute(getConnection(), getDataSet());
}
/**
* Required by DbUnit
*/
protected IDataSet getDataSet() throws Exception {
loadedDataSet = DbUnitHelper.getDataSetFromFile(getConnection(), "TestData.xml");
return loadedDataSet;
}
/**
* Required by DbUnit
*/
protected IDatabaseConnection getConnection() throws Exception{
return new DatabaseConnection(dataSourceA.getConnection());
}
@Test
public void testSomething() {
// service.doCopyStuff();
}
}
Проблема, как я ее вижу, заключается в том, что @TransactionConfiguration
указывает только целевой источник данных для включения отката. DBUnit передается dataSourceA
явно и собирает диспетчер транзакций по умолчанию с именем transactionManager
(я не уверен, Как), который не был уведомлен об откате.
Вопрос
Как я могу сказать обоим менеджерам транзакций откатиться?
Могу ли я использовать один диспетчер транзакций, если мои источники данных не поддерживают XA сделки?
Примечание: приложение не требует менеджера транзакций на dataSourceA при запуске в рабочей среде, так как оно будет доступно только для чтения. Эта проблема касается только моих классов тестов.
3 ответа:
Возможным обходным путем было бы ввести вспомогательный боб с аннотацией
@Transactional("transactionManagerTarget")
и оставить ваш тест с аннотацией@Transactional("transactionManager")
, настроив оба сdefaultRollback = true
. Затем тест должен будет вызвать вспомогательный компонент, который, в свою очередь, вызовет тестируемый компонент службы. Это должно привести к откату транзакции вокруг вашего сервиса, а затем транзакции вокруг DBUnit.Это немного грязно, хотя.
Другие возможные подходы:
- использование базы данных в памяти, такой как H2 вместо вашей производственной базы данных-вы можете настроить это, чтобы удалить все свои данные, когда это необходимо.
- разрешите DBUnit совершить коммит и выполните компенсирующую транзакцию в своем методе разборки, чтобы очистить данные.
Используйте элемент
<qualifier>
в определении диспетчера транзакций.<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSourceA" /> <qualifier value="transactionManager" /> </bean> <bean id="transactionManagerTarget" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSourceB" /> <qualifier value="transactionManagerTarget" /> </bean>
Затем вы можете указать, какой из них вы хотите использовать непосредственно в аннотации
@Transactional
, т. е.@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:resources/spring-context.xml", "classpath:resources/spring-db.xml"}) @Transactional("transactionManagerTarget") @TransactionConfiguration(defaultRollback = true) public class MyIntegrationTest { ...
Я использовал транзакции XA и откаты в тестах JUnit с открытым исходным кодом TM Atomikos. Одной из приятных особенностей является то, что Atomikos позволяет использовать источники данных, не включенные в XA, для участия в транзакциях XA. Проверьте эту ссылку для примера: http://www.atomikos.com/Documentation/NonXaDataSource
С другой стороны, если XA является достойным решением для ваших проблем JUnit-это другая история. Ваши тесты фокусируются много на реализации базы данных (Sybase) или это больше о Java логика? Обычно я настраиваю встроенные базы данных, такие как Apache Derby или HQSQL, для тестов JUnit. Тогда мне не нужно много заботиться о чистоте, так как GC справится с этим :)