所以我有一个类:
@Service
public class MyService {
@Autowired
private RepositoryA repoA;
@Autowired
private RepositoryB repoB;
@Transactional
public void storeEntity(SomeEntity e) {
repoA.save(e);
OtherEntity o = doSomethingWithEntity(e);
repoB.save(o);
}
}
我的方法storeEntity
对两个不同的数据源进行两次保存。我希望如果保存到 repoB 失败,或者 doSomethingWithEntity
失败,repoA.save(e)
将回滚。
我想编写一个小测试来确保这种行为:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceForTransactionTest {
@Autowired
private MyService subject;
@Autowired
private RepositoryA repoA;
@MockBean
private RepositoryB repoB;
@Test
public void repoBShouldNotHaveEntries() {
// given
when(repoB.save(any())).thenThrow(new IllegalStateException("Something wrong with db"));
assertThat(repoB.count()).isEqualTo(0);
// when
SomeEntity e = ...
subject.storeEntity(e);
// then
assertThat(repoA.count()).isEqualTo(0);
}
}
这不起作用,因为抛出异常并且测试失败。当我用 try/catch 包围调用时,我的断言失败,并显示一条消息:repoA 有 1 个条目。如何解决这个问题?
我也尝试过这个:
@Test
public void repoBShouldNotHaveEntries() {
// given
when(repoB.save(any())).thenThrow(new IllegalStateException("Something wrong with db"));
assertThat(repoB.count()).isEqualTo(0);
// when
SomeEntity e = ...
try {
subject.storeEntity(e);
} catch (Exception e) {
// some output here
}
// then
assertThat(repoA.count()).isEqualTo(0);
}
断言失败。我也尝试过这个:
@Test
public void repoBShouldNotHaveEntries() {
// given
when(repoB.save(any())).thenThrow(new IllegalStateException("Something wrong with db"));
assertThat(repoB.count()).isEqualTo(0);
// when
SomeEntity e = ...
subject.storeEntity(e);
}
@After
public void tearDown() {
// then
assertThat(repoA.count()).isEqualTo(0);
}
}
也失败了。找到 1 条记录,但我希望 @Transactional
应该回滚。
最佳答案
当您通过 Spring 管理事务时,您实际上是在使用抽象。对于单个数据源(通常称为资源本地事务),事务启动/提交/回滚将按预期工作,但如果使用两个不同的数据源,那么您需要一个能够执行分布式事务的事务管理器,如 Bitronix或Atomikos Essentials (在开源世界中)。在 EE 应用服务器环境中,此功能由服务器本身提供。 Here是一篇非常古老的文章,值得一读(它使用一个数据库和一个消息代理参与分布式事务,但概念是相同的 - 关键是多个资源)。有关 Bitrionix 和 Spring 的示例配置,请查看 this出来。
关于java - 为什么@Transactional 在另一项提交失败时不回滚一项提交?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58195292/