Spring @Transactional 和回滚不起作用,弹簧集成测试

Posted

技术标签:

【中文标题】Spring @Transactional 和回滚不起作用,弹簧集成测试【英文标题】:Spring @Transactional and rollback not working, spring integration tests 【发布时间】:2020-06-20 03:26:26 【问题描述】:

我在 spring 中做一个集成测试,在这个例子中我测试一个服务层。

我有一个问题,在服务的添加测试期间,回滚不起作用,并且总是将一个项目添加到基础,但不删除它。

我把注解@Transactional和@TestPropertySource放在测试类上, 也有 application-test.properties 并且测试成功但没有执行回滚,并且总是将新项目添加到测试数据库中。

我的添加地址的测试类和测试方法(最后一个):

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TicketServiceApplication.class)
@Transactional
@TestPropertySource("classpath:application-test.properties")
public class AddressServiceIntegrationTest 


@Autowired
private AddressService addressService;

@Autowired
private AddressRepository addressRepository;

@Test
public void findAllSuccessTest()
    List<Address> result = addressService.finfAllAddress();

    assertNotNull(result);
    assertFalse(result.isEmpty());
    assertEquals(2, result.size());


@Test
public void findOneAddressExistTest_thenReturnAddress()
    Long id = AddressConst.VALID_ID_ADDRESS;
    Address a = addressService.findOneAddress(id);
    assertEquals(id, a.getId());


@Test(expected = EntityNotFoundException.class)
public void findOneAddressNotExistTest_thenThrowException()
    Long id = AddressConst.NOT_VALID_ID_ADDRESS;
    Address a = addressService.findOneAddress(id);


@Test
public void addAddressSuccessTest()

    int sizeBeforeAdd = addressRepository.findAll().size();

    Address address = AddressConst.newAddressToAdd();
    Address result = addressService.addAddress(address);

    int sizeAfterAdd  = addressRepository.findAll().size();

    assertNotNull(result);
    assertEquals(sizeBeforeAdd+1, sizeAfterAdd);
    assertEquals(address.getCity(), result.getCity());
    assertEquals(address.getState(), result.getState());
    assertEquals(address.getNumber(), result.getNumber());
    assertEquals(address.getLatitude(), result.getLatitude());
    assertEquals(address.getLongitude(), result.getLongitude());
    assertEquals(address.getStreet(), result.getStreet());


我的应用程序-test.properties:

spring.datasource.url= jdbc:mysql://localhost:3306/kts_test&useSSL=false&
useUnicode=true&characterEncoding=utf8
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.show-sql = true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

并且在执行添加地址测试时,每次在我的 kts_test 数据库(用于测试的 db)中都会添加新项目而不是回滚。

这是来自控制台的日志,您可以在其中看到回滚被调用但没有执行,因为当我在测试后刷新数据库时,留下了新项目,它没有被删除。

INFO 10216 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test: [DefaultTestContext@3e58a80e testClass = AddressServiceIntegrationTest, testInstance = com.ftn.services.address.AddressServiceIntegrationTest@4678ec43, testMethod = addAddressSuccessTest@AddressServiceIntegrationTest, testException = [null],...

最后要写的是我试过@Transactional上面的方法,我也试过@Rollback上面的方法或者@Rollback(true),试过改application-test.properties,我已经不知道错误可能是什么了。

如果有人能提供帮助,我将不胜感激。谢谢。

【问题讨论】:

你在 MySQL 中使用什么存储引擎? 当我使用显示引擎时,我得到 InnoDB 是默认值。 但是现在我使用 SHOW TABLE STATUS,引擎是 MyISAM ! 日本,但 Hibernate 可以根据方言创建具有不同引擎的表。您可以尝试设置:spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 好的,我现在试试你告诉我的 wright。我将方言添加到 prperties 文件中,并且再次不回滚。 【参考方案1】:

Hibernate 默认使用 MyISAM 存储引擎创建表 - 该引擎不支持事务。你需要有 InnoDB 表:

要么使用 Flyway 等工具手动管理数据库迁移(恕我直言,因此您可以完全控制),并在测试中关闭重新创建数据库。 或者在配置中设置正确的引擎:
spring.jpa.properties.hibernate.dialect.storage_engine=innodb

OR(已弃用)

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

【讨论】:

如果我在数据库和应用程序库和测试库中都将引擎更改为innodb,应用程序会出现问题吗? 你有什么问题?如果您担心不同的行为/功能,可以回答一些关于此的问题:***.com/questions/12614541/… 希望它会有所帮助。 .)

以上是关于Spring @Transactional 和回滚不起作用,弹簧集成测试的主要内容,如果未能解决你的问题,请参考以下文章

你知道@Transactional注解的失效场景吗?

Spring——Spring中的事务使用注解(@Transactional)控制事务使用AspectJ框架控制事务

Spring事务控制和回滚

Spring中@Transactional事务回滚

Spring 数据和 mongodb - 在 @Transactional 中使用 spring 进行简单回滚

Spring @Transactional注解不回滚不起作用无效