Spring Boot 2中的SpringBootTest无法回滚事务

4

我有一个非常简单的Spring测试,使用@DataJpaTest@Transactional

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
@Transactional
@Rollback
@ComponentScan(basePackages = "com.acma")
public class FooTest {
  @Autowired
  private EntityManager em;

  @Test
  public void persist() throws Exception {
    em.persist(new Foo());
  }
}

@Entity
public class Foo {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
}

根据文档,每个测试用例都应该在自己的事务中运行,并在每个测试用例结束时回滚,但实际情况并非如此。更奇怪的是,在日志中我看到了:
2018-05-02 19:47:07.246  INFO 97919 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@317890ea testClass = FooTest, testInstance = com.acma.FooTest@2c719bd4, testMethod = persist@FooTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@53aa38be testClass = FooTest, locations = '{}', classes = '{class com.acma.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@37a0ec3c key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@5be6e01c, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7ce3cb8e, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@70e8f8e, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@e831c7a, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@636be97c], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@6f9e08d4]; rollback [true]
Hibernate: insert into foo values ( )
2018-05-02 19:47:07.575  INFO 97919 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [DefaultTestContext@317890ea testClass = FooTest, testInstance = com.acma.FooTest@2c719bd4, testMethod = persist@FooTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@53aa38be testClass = FooTest, locations = '{}', classes = '{class com.acma.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@37a0ec3c key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@5be6e01c, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@7ce3cb8e, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@70e8f8e, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@e831c7a, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@636be97c], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map[[empty]]].

你是在哪个阶段/时间点尝试验证事务是否已经回滚? - crizzis
1个回答

1

@DataJpaTest 默认情况下,数据 JPA 测试是事务性的,并在每个测试结束时回滚

因此您不需要额外的 @Transactional & @Rollback

这里有一个示例,请查看 @AfterTransaction 及其输出。

在您的示例中,您可以尝试在此方法中检索保存的实体,但您将找不到它。

 @RunWith(SpringRunner.class)
 @DataJpaTest
 public class TransactionTest {

   @Autowired PersonRepository repo;

   @Before
   public void showCountBefore() {
     System.err.println("before: " + repo.count());
   }

   @After
   public void showCountAfter() {
    System.err.println("after: " + repo.count());
   }

   @AfterTransaction
   public void showCountAfterTransaction() {
     System.err.println("after tx: " + repo.count());
   }

   @Test
   public void testRollback() {
     repo.save(new Person("Deyne", "Dirk", "dirkdeyne"));
     System.err.println("saved: " + repo.count());
   }

}

这将打印输出

  • 之前:5
  • 已保存:6
  • 之后:6
  • tx之后:5

我已经更改了我的示例,删除了您提到的注释,但没有帮助,这是修改后的版本:https://gist.github.com/csokol/a37356da3400d57edc1e460e9674efdc也许原因是我没有使用内存数据库?另外,我正在使用Spring Boot 2.x... - Chico Sokol
是的,当我将其更改为使用内存数据库(删除@AutoConfigureTestDatabase(replace = Replace.NONE))时,事务回滚起作用了。 - Chico Sokol
这很奇怪!@AutoConfigureTestDatabase(replace = Replace.NONE) 在我的示例中没有任何区别。我尝试使用EntityManager persist,它也可以工作...也许你需要在persist之后刷新em.flush(); - Dirk Deyne
你正在使用哪个Spring Boot版本? - Chico Sokol
@DirkDeyne 我用这个链接 https://dev59.com/j6rka4cB1Zd3GeqPYBTK#49997835 解决了问题。 - Richa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接