2016-11-29 28 views
1

工作代码:弹簧试验的@Rollback不会回退以下任何

//import everything 

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = Test2.TestConfiguration.class) 
@Transactional 
public class Test2 { 

    @Autowired 
    private DataSource datasource; 

    @BeforeTransaction 
    public void createDatabase() throws SQLException { 
     DataSourceUtils .getConnection(datasource) 
         .createStatement() 
         .execute("CREATE TABLE USERS (id bigint, size bigint, primary key (id))"); 
    } 

    @Rollback 
    @Test 
    public void test() throws SQLException { 
     DataSourceUtils .getConnection(datasource) 
         .createStatement() 
         .execute("INSERT INTO USERS VALUES (5, 5)"); 
    } 

    @AfterTransaction 
    public void dropTable() throws SQLException { 
     ResultSet rs = DataSourceUtils .getConnection(datasource) 
             .createStatement() 
             .executeQuery("SELECT * FROM USERS"); 
     boolean isEmpty = !rs.next(); 
     if (isEmpty) { 
      System.out.println("Rollback succeeded"); 
     } else { 
      System.out.println("Rollback failed"); 
     } 
     rs.close(); 

     datasource .getConnection() 
        .createStatement() 
        .execute("DROP TABLE USERS"); 
    } 

    @Configuration 
    public static class TestConfiguration { 

     @Bean 
     public DataSource driverManagerDataSource() { 
      DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(); 
      String dbURI = "database/tests/DerbyDB/db"; 
      String connectionString = "jdbc:derby:" + dbURI; 
      if (!new File(dbURI).exists()) connectionString += ";create=true"; 
      driverManagerDataSource.setUrl(connectionString); 
      driverManagerDataSource.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver"); 
      return driverManagerDataSource; 
     } 

     @Bean 
     public PlatformTransactionManager platformTransactionManager() { 
      PlatformTransactionManager ptm = new DataSourceTransactionManager(driverManagerDataSource()); 
      return ptm; 
     } 
    } 
} 

解决问题: 我想用@Rollback注释每次测试后回滚数据库状态。不幸的是它不起作用。

这里是我的测试类:

//import everything 

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = Test2.TestConfiguration.class) 
@Transactional 
public class Test2 { 

    @Autowired 
    private DataSource datasource; 

    @BeforeTransaction 
    public void createTable() throws SQLException { 
     datasource .getConnection() 
        .createStatement() 
        .execute("CREATE TABLE USERS (id bigint, size bigint, primary key (id))"); 
    } 

    @Rollback 
    @Test 
    public void test() throws SQLException { 
     datasource .getConnection() 
        .createStatement() 
        .execute("INSERT INTO USERS VALUES (5, 5)"); 
    } 

    @AfterTransaction 
    public void dropTable() throws SQLException { 
     ResultSet rs = datasource .getConnection() 
            .createStatement() 
            .executeQuery("SELECT * FROM USERS"); 
     boolean isEmpty = !rs.next(); 
     if (isEmpty) { 
      System.out.println("Rollback succeeded"); 
     } else { 
      System.out.println("Rollback failed"); 
     } 
     rs.close(); 

     datasource .getConnection() 
        .createStatement() 
        .execute("DROP TABLE USERS"); 
    } 

    @Configuration 
    public static class TestConfiguration { 

     @Bean 
     public DataSource driverManagerDataSource() { 
      DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(); 
      String dbURI = "database/tests/DerbyDB/db"; 
      String connectionString = "jdbc:derby:" + dbURI; 
      if (!new File(dbURI).exists()) connectionString += ";create=true"; 
      driverManagerDataSource.setUrl(connectionString); 
      driverManagerDataSource.setDriverClassName("org.apache.derby.jdbc.EmbeddedDriver"); 
      return driverManagerDataSource; 
     } 

     @Bean 
     public PlatformTransactionManager platformTransactionManager() { 
      PlatformTransactionManager ptm = new DataSourceTransactionManager(driverManagerDataSource()); 
      return ptm; 
     } 
    } 
} 

春声称,它回滚数据库,这是不正确的,因为记录仍然存在。
如何让它工作?

gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext startTransaction 
INFO: Began transaction (1) for test context [[email protected] testClass = Test2, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [o[email protected]3bf9ce3e]; rollback [true] 
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction 
INFO: Rolled back transaction for test context [[email protected] testClass = Test2, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]. 
Rollback failed 
gru 01, 2016 12:26:14 PM org.springframework.context.support.GenericApplicationContext doClose 
INFO: Closing [email protected]45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy 

完整的日志介绍如下:

gru 01, 2016 12:26:12 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames 
INFO: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] 
gru 01, 2016 12:26:12 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners 
INFO: Using TestExecutionListeners: [or[email protected]69d9c55, org.springframework.test[email protected]13a57a3b, org.springframewor[email protected]7ca48474, org.springfra[email protected]337d0578, org.springframew[email protected]59e84876, org.sp[email protected]61a485d2] 
gru 01, 2016 12:26:12 PM org.springframework.context.support.GenericApplicationContext prepareRefresh 
INFO: Refreshing [email protected]45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy 
gru 01, 2016 12:26:13 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init> 
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring 
gru 01, 2016 12:26:13 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName 
INFO: Loaded JDBC driver: org.apache.derby.jdbc.EmbeddedDriver 
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext startTransaction 
INFO: Began transaction (1) for test context [[email protected] testClass = Test2, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [o[email protected]3bf9ce3e]; rollback [true] 
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction 
INFO: Rolled back transaction for test context [[email protected] testClass = Test2, testInstance = [email protected], testMethod = [email protected], testException = [null], mergedContextConfiguration = [[email protected] testClass = Test2, locations = '{}', classes = '{class tyvrel.tastas.persistence.Test2$TestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]. 
Rollback failed 
gru 01, 2016 12:26:14 PM org.springframework.context.support.GenericApplicationContext doClose 
INFO: Closing [email protected]45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy 

回答

2

据我所知,你在你的测试方法,它的初始化过程中创建表手动创建一个新的,独立的Spring上下文。

由于该上下文使用自己的事务管理器和数据源,因此不会受到@Rollback注释的影响 - 它是在为整个测试类定义的(隐式)弹簧上下文的上下文中处理的。


还要注意,在一些数据块,就不能再回退到CREATE命令(不知道德比虽然)。


更新

的另一个问题是,你实际上并没有使用事务管理器,当你打通datasource.getConnection()连接。

DataSourceTransactionManager文档:

应用程序代码就可以检索通过DataSourceUtils.getConnection(DataSource),而不是一个标准的Java EE风格DataSource.getConnection()通话的JDBC连接。 Spring类如JdbcTemplate隐式使用此策略。

+0

您是不是说,使用'@ContextConfiguration(classes = TestDerbyDatabaseInitializer.TestConfiguration.class)'注释测试类并删除implict context会使'@ Rollback'注释起作用? – Tyvrel

+1

1)您需要使用'@ ContextConfiguration'注释创建的Spring上下文(即做你写的);不要创建任何其他上下文以避免混淆,2)不要以编程方式创建任何与数据库的其他连接('DriverManager.getConnection()'),以避免意外使用非托管连接,3)根据您知道的事情对其进行测试可以回滚(即'INSERT',而不是'CREATE TABLE') - 在'@ BeforeTransaction'方法中创建数据库。 –

+0

谢谢,那个答案让我更加了解测试Spring的知识。此外,我已经根据您的评论更新了代码,但仍然无法正常工作。 – Tyvrel

0

我觉得这行con.close();printTableName()方法引起的问题。

关闭连接时提交事务。

最好用entitymanagerspring data jpa repository来处理交易。

+0

不幸的是,删除'con.close();'并不能解决问题。 – Tyvrel

+0

@Tyvrel你试过显式回滚吗? 'con.rollback();' – Bryan

+0

当然。它也不起作用。并忽略了一点 - 我需要了解'@ Rollback'是如何工作的,而且我无法找到比执行简单的sql脚本更简单的练习。 – Tyvrel