java - Spring-test 的 @Rollback 不会回滚任何内容

标签 java transactions spring-test

下面的工作代码:

//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;
        }
    }
}

Spring 声称它回滚了数据库,但这不是真的,因为记录仍然存在。
我该如何让它发挥作用?

gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext startTransaction
INFO: Began transaction (1) for test context [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 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 [org.springframework.jdbc.datasource.DataSourceTransactionManager@3bf9ce3e]; rollback [true]
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction
INFO: Rolled back transaction for test context [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 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 org.springframework.context.support.GenericApplicationContext@ae45eb6: 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: [org.springframework.test.context.web.ServletTestExecutionListener@69d9c55, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@13a57a3b, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@7ca48474, org.springframework.test.context.support.DirtiesContextTestExecutionListener@337d0578, org.springframework.test.context.transaction.TransactionalTestExecutionListener@59e84876, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@61a485d2]
gru 01, 2016 12:26:12 PM org.springframework.context.support.GenericApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.GenericApplicationContext@ae45eb6: 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 [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 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 [org.springframework.jdbc.datasource.DataSourceTransactionManager@3bf9ce3e]; rollback [true]
gru 01, 2016 12:26:14 PM org.springframework.test.context.transaction.TransactionContext endTransaction
INFO: Rolled back transaction for test context [DefaultTestContext@457c9034 testClass = Test2, testInstance = tyvrel.tastas.persistence.Test2@345f69f3, testMethod = test@Test2, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@e15b7e8 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 org.springframework.context.support.GenericApplicationContext@ae45eb6: startup date [Thu Dec 01 12:26:12 CET 2016]; root of context hierarchy

最佳答案

据我了解,您正在测试方法中手动创建一个新的、独立的 Spring 上下文,该上下文在初始化期间会创建表。

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


另请注意,在某些数据库中,您无法回滚 CREATE 命令(但不确定 Derby)。


更新

另一个问题是,当您通过 datasource.getConnection() 获取连接时,您实际上并没有使用事务管理器。

来自DataSourceTransactionManager文档:

Application code is required to retrieve the JDBC Connection via DataSourceUtils.getConnection(DataSource) instead of a standard Java EE-style DataSource.getConnection() call. Spring classes such as JdbcTemplate use this strategy implicitly.

关于java - Spring-test 的 @Rollback 不会回滚任何内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40869415/

相关文章:

java - 如何创建一个 ArrayList,我也可以像 Java 一样添加项目

java - 如何按顺序对属性文件值进行排序?

java - 添加到表后读取数据返回零

java - 避免对 Spring 配置类进行类路径扫描

spring - 如何与 HtmlUnit 共享 MockMvc session ?

java - 如何解析 Retrofit 2 响应以显示数据?

.net - 为什么 System.IO.Log SequenceNumbers 具有可变长度?

mysql - MySQL 是否在单个 DML 修改数据中使用事务并自动提交?

java - 升级到 Spring 3 和 junit 11 - 运行测试后上下文变为 null。没有可用于第二次测试的 Autowiring bean

java - 当我在 Android Studio 上运行我的应用程序时,模拟器启动,但它说测试应用程序崩溃了