Rollback not working on Spring Boot @Transactional method for H2 database

Viewed 102

Please give me tips to get my failing JUnit test to pass in my Spring Boot app.

I have a Service that needs to delete rows from tables A and B (from a H2 database) in a transactional manner such that: if A is modified and then an exception occurs before B is modified, then neither A nor B are modified. However, even after 

  1. Adding @Transactional to the PUBLIC Service::deleteRows method, and
  2. Adding @EnableTransactionManagement to the @Configuration class that produces the JdbcTemplate that all repositories use, and
  3. Confirming that spring-tx is on the classpath

the transaction still doesn't rollback.

Here's the failing JUnit testcase

// Service.java
@Transactional
public void deleteRows() {
    aRepository.deleteRow(123);
    bRepository.deleteRow(123);
}
// ServiceTest.java
@Test
void test() {​
    // first ensure that an exception is thrown when bRepository.deleteRow() is called
    // FYI deleteRow() calls jdbcTemplate.update()
    doThrow(RuntimeException.class)
        .when(mockJdbcTemplate)
        .update(any(), eq(123));
    BRepository mockBRepository = new BRepository(mockJdbcTemplate);
    Service service = new Service(realARepository, mockBRepository);

    assertTableHasRows(1, "TABLE_A");                          // before calling the service, TABLE_A has 1 row

    assertThrows(RuntimeException.class, service::deleteRows);    

    assertTableHasRows(1, "TABLE_A");                          // TABLE_A should still have 1 row when an exception occurs during the tx
}​
2 Answers

Remove @Transactional and run test again.

In the end the problem was solved by NOT using mocking to trigger an exception. Instead, we set up the database schema so that normal operation of service::deleteRows would trigger an exception.

Related