当前位置: 首页 > 知识库问答 >
问题:

DBUnit和Spring Boot-在联调中请求时可能无法导入或存在数据

姜聪
2023-03-14

如果我使用以下设置运行dbUnit并在联调中通过HTTP请求数据,我没有得到任何数据,因为数据库是空的。DBUnit将数据写入数据库,但当我通过HTTP请求数据时,它是空的。

这是我的设置:Spring Boot 1.1.7 with spring-boot-starter-web(不包括tomcat)、spring-boot-starter-jetty、spring-boot-starter-data-jpa、spring-boot-starter-test、liquibase-core、dbUnit 2.5.0、spring-test-dbUnit 1.1.0

主要应用类别:

@Configuration
@ComponentScan
@EnableAutoConfiguration
@RestController
@EnableTransactionManagement
@EnableJpaRepositories

测试配置(应用测试.yaml):

logging.level.org.springframework: DEBUG
logging.level.org.dbunit: DEBUG

spring.jpa.properties.hibernate.hbm2ddl.auto: update
spring.jpa.database: h2
spring.jpa.show-sql: true

// setting these properties to access the database via h2 console
spring.datasource.url: jdbc:h2:tcp://localhost/mem:my_db;DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username: sa
spring.datasource.password: sa
spring.datasource.driverClassName: org.h2.Driver
spring.jpa.database-platform: org.hibernate.dialect.H2Dialect

liquibase.change-log: classpath:/db/changelog/db-master.xml

集成测试:

@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = HDImageService.class)
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    DbUnitTestExecutionListener.class })
@WebAppConfiguration
@IntegrationTest("server.port:0")
@DatabaseSetup("/database_seed.xml")
@DatabaseTearDown(value = "/database_tear_down.xml", type = DatabaseOperation.DELETE_ALL)

// test
@Test
public void get_works() throws Exception {
    // given
    String url = host + port + "/my-resource/1";

    // when
    ResponseEntity<String> response = template.getForEntity(url, String.class);

    // then
    assertThat(response.getStatusCode(), is(HttpStatus.OK));
}

我可以在这里发布其他所有内容,例如实体、存储库、控制器,...但是这些组件正在工作,因为我已经通过注入的存储库在测试中写入数据库并通过HTTP获取它。所以问题是通过dbUnit导入,这不起作用...我已经在较旧的投影中成功使用了dbUnit,但没有与Spring启动一起使用。也许执行侦听器的工作方式与Spring启动不相似?

我调试抛出了dbunit类并读取了所有调试日志输出,但我没有得到它。DBUnit使用的是spring boot创建的数据源(上面配置的),所以它是同一个数据库。

开始集成测试时,会发生以下情况:
-liquibase根据liquibase配置创建数据库模式(也许jpa之前已经推送了模式?)
-DBUnit插入数据库(表示日志输出和调试)
-找不到404(当在数据库中没有找到具有给定ID的条目时,我返回404)

更新:

我正在寻找dbUnit的替代品,但找不到任何好的解决方案。那么如何为集成测试准备数据库呢?实际上,我只需要在每次测试或测试之前导入个人数据,如果数据按预期持久化。

更新:

我使用以下选项连接到h2数据库:

DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE

当我拆下整个Spring时。数据源。*configuration spring正在使用标准值创建数据源,并启动内存中的h2数据库服务器。这将在没有我提到的选项的情况下完成,我会得到一个组织。冬眠因为dbunit仍然锁定数据库表,并且在测试内部发送的HTTP请求无法访问数据库表,所以悲观锁异常(悲观锁异常)。这是因为选项MVCC=true 增加了更高的并发性,基本问题是什么,为什么不存在数据:“连接只‘看到’提交的数据和自己的更改”。当通过HTTP请求访问数据库时,dbunit的数据不存在,因为dbunit的数据没有提交给spring连接。。。

那么,有人知道为什么h2(以及derby)数据库表被dbunit锁定吗?

共有1个答案

齐琦
2023-03-14

我终于找到了解决这个问题的办法。

我指向的PessimisticLockException是正确的方向。DBUnit没有释放数据库连接,这就是为什么Spring的连接无法访问锁定的数据库表。

我实现了自己的数据库操作。我使用该选项自定义DBUnit数据库选项。

首先,我基于DBUnit的TransactionOperation实现了一个名为AutoCommitTransactionOperation的类,不同的是我删除了检查jdbcConnection。getAutoCommit()==false,并在将自动提交设置为false之前保存了自动提交值。提交后,我将该值设置回保存的值,使其具有与之前相同的状态:

public class AutoCommitTransactionOperation extends DatabaseOperation {

    private final DatabaseOperation _operation;

    public AutoCommitTransactionOperation(DatabaseOperation operation) {
        _operation = operation;
    }

    public static final DatabaseOperation AUTO_COMMIT_TRANSACTION(DatabaseOperation operation) {
        return new AutoCommitTransactionOperation(operation);
    }

    public void execute(IDatabaseConnection connection, IDataSet dataSet) throws DatabaseUnitException, SQLException {
        logger.debug("execute(connection={}, dataSet={}) - start", connection, dataSet);

        IDatabaseConnection databaseConnection = connection;
        Connection jdbcConnection = databaseConnection.getConnection();

        boolean autoCommit = jdbcConnection.getAutoCommit();
        jdbcConnection.setAutoCommit(false);
        try {
            _operation.execute(databaseConnection, dataSet);
            jdbcConnection.commit();
        } catch (DatabaseUnitException e) {
            jdbcConnection.rollback();
            throw e;
        } catch (SQLException e) {
            jdbcConnection.rollback();
            throw e;
        } catch (RuntimeException e) {
            jdbcConnection.rollback();
            throw e;
        } finally {
            jdbcConnection.setAutoCommit(autoCommit);
        }
    }
}

然后我创建了数据库查找。

public class AutoCommitTransactionDatabaseLookup extends DefaultDatabaseOperationLookup {

    @Override
    public org.dbunit.operation.DatabaseOperation get(DatabaseOperation operation) {
        if (operation == operation.CLEAN_INSERT) {
            return AutoCommitTransactionOperation.AUTO_COMMIT_TRANSACTION(org.dbunit.operation.DatabaseOperation.CLEAN_INSERT);
        }
        return super.get(operation);
    }
}

并将其添加到我的测试类:

@DbUnitConfiguration(databaseOperationLookup = AutoCommitTransactionDatabaseLookup.class)

我不确定这更多的黑客...对我的黑客有什么暗示吗?

 类似资料:
  • 从我的后端应用程序(springboot,java8)中,我将进行多个外部api调用。我需要将所有请求和响应数据(包括头、请求和响应体)记录到数据库(MongoDB)中。 下面是我的示例代码,这是我如何尝试捕获每个外部api调用的请求和响应。在异常情况下,我将存储状态为“失败”。 在我的项目中,将在新的第三方api集成上添加多个模块,因此在每个模块中,对于每个不同的外部api调用,我必须捕获所有这

  • 我正在用Cordova开发一个Android应用程序。我有一个自定义插件试图使用OKHTTP。 我错过了什么?通过查看OKHTTP的源代码和它们的示例,这些类肯定是公共的。此外,我从导入的其他内容也很好... 谢了!

  • 我有2个JParepository: 为了保存一份有几个参与者的新合同,我正在邮递员中执行以下步骤: 创建契约并获取其href: 没运气。出于某种原因,系统将该字段留空,而不是使用步骤1中创建的实体的foreing键。我做错了什么?

  • 我试图使用Ubuntu 16.04在亚马逊AWS上部署我的Django项目。我正在运行python版本2.7.12和Django 1.10.5。我创建了名为venv的虚拟环境,然后激活了它。我得到这个错误,当我试图运行pythonmanage.pyrunserver。 Traceback(最近一次调用最后一次):文件"manage.py",第17行,在"不能导入Django。你确定它安装和"重要错

  • 问题内容: 为什么会发生这种情况? 结果是: 如果可以的话,它可以很好地加载模块,但是加载时似乎不起作用。 有关一些可能相关的其他信息: 我保存文件的模块在中。该模块。开始: 我试图从中加载的模块在in中,而不会弄乱路径。 在两种情况下都是相同的:我要加载的模块是。 可能以某种方式将附加内容弄乱吗? 问题答案: 泡菜取决于模块路径。不管您如何加载模块,如果您不介意的话,泡菜的加载和保存都应该起作用

  • 问题内容: 我最近在这里使用Windows 32位安装程序将PyQt5从5.5.1升级到了5.6.0:https ://www.riverbankcomputing.com/software/pyqt/download5 。我还将python从3.4升级到3.5。 当我使用最新版本运行旧代码(该代码曾经可以工作)时,出现异常: 我在python中进行的所有QT调用都是连续发生的(并且,我知道我不应