如何使用Spring+;DBUnit+;朱尼特
简而言之 我的命令行Java应用程序将数据从一个数据源复制到另一个数据源,而不使用XA。我已经配置了两个独立的数据源,并且想要一个JUnit测试,它可以回滚两个数据源上的数据。我使用DBUnit将数据加载到“源”数据库中,但无法使其回滚。我可以让“目标”数据源回滚 我的代码 给定此配置如何使用Spring+;DBUnit+;朱尼特,spring,junit,dbunit,spring-transactions,Spring,Junit,Dbunit,Spring Transactions,简而言之 我的命令行Java应用程序将数据从一个数据源复制到另一个数据源,而不使用XA。我已经配置了两个独立的数据源,并且想要一个JUnit测试,它可以回滚两个数据源上的数据。我使用DBUnit将数据加载到“源”数据库中,但无法使其回滚。我可以让“目标”数据源回滚 我的代码 给定此配置 <tx:annotation-driven /> <!-- note the default transactionManager name on this one --> <be
<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>
在我看来,问题在于@TransactionConfiguration
仅说明用于启用回滚的目标数据源。DBUnit正在显式传递dataSourceA
,并正在获取名为transactionManager
(我不确定如何)的默认事务管理器,该事务管理器未被告知回滚
问题
如何告诉两个事务管理器回滚
当我的数据源不支持XA事务时,我可以使用单个事务管理器吗
注意:应用程序在生产中运行时不需要dataSourceA上的事务管理器,因为它只会是只读的。此问题仅适用于我的测试类。在事务管理器定义中使用
元素
<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>
我使用开源TM Atomikos在JUnit测试中使用了XA事务和回滚。一个很好的特性是Atomikos允许使用未启用XA的数据源参与XA事务。查看此链接以获取示例:
另一方面,如果XA是解决JUnit问题的合适解决方案,那就另当别论了。您的测试主要关注数据库实现(Sybase)还是更多地关注Java逻辑?我通常为JUnit测试设置嵌入式数据库,如ApacheDerby或HQSQL。那么我就不必太在意清理了,因为GC会处理:)一个可能的解决方法是引入一个注释为
@Transactional(“transactionManagerTarget”)
的助手bean,并将您的测试注释为@Transactional(“transactionManager”)
,使用defaultRollback=true
配置两者。然后,您的测试必须调用helperbean,而helperbean又将调用您的测试服务bean。这将导致围绕服务的事务回滚,然后围绕DBUnit的事务回滚
不过有点乱
其他可能的办法:
- 使用内存中的数据库(如H2)而不是生产数据库-您可以将其配置为在需要时删除其所有数据
- 允许DBUnit提交,并在拆卸方法中使用补偿事务来清除数据
@Before
和@Test
方法将在同一事务中执行,我无法指定多个@Transactional注释。在您的回答中,我看不出它是如何告诉transactionManager
回滚的。我错过什么了吗?不过,使用
很好。我在我的测试类上尝试了@Transactional
的各种用法,但不幸的是,我怀疑@test
方法启动了一个事务,而@Before
无法为DBUnit启动另一个事务,因此它继续与transactionManagerTarget一起运行,因此不会回滚DBUnit数据。我想我尝试了所有我能使用的注释,但没有运气。谢谢你的回复。DBUnit仅用于加载测试数据,因为该数据源已经由另一个服务在生产中填充。因此,我在生产中没有XA问题,因为我只向一个目标数据源写入数据。我喜欢您将HSQL用于我的“源”数据源的想法。我只需要弄清楚如何存储我的模式以供HSQL加载,并使其与Sybase模式保持一致。任何JTA TM对我都没有好处,因为我的两个数据源都不是XA。大多数JTA TM允许您使用一个非XA数据源,但不允许使用很长的时间,但是。。跳过HQSQL,对其中一个数据源(源)使用ApacheDerby。不能将架构存储在test/resources/source\u db\u setup.sql中吗?Derby已启用XA。然后可以使用sybase作为非xa源。我认为应该有一些其他的选择给你,虽然,我现在没有什么好主意。我试着分解出一个helperbean,但这并没有帮助我们进行转换。当有多个TransactionManager时,后台数据库单元不会回滚。我将接受您的答案,使用HSQL作为前进的方向,但是在我的例子中,我仍然被卡住了,因为我使用Sybase在这个数据源上创建了一个临时表,并且语法与HSQL不兼容。
<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>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:resources/spring-context.xml",
"classpath:resources/spring-db.xml"})
@Transactional("transactionManagerTarget")
@TransactionConfiguration(defaultRollback = true)
public class MyIntegrationTest {
...