简体   繁体   English

使用 r2dbc 和 flyway 在 Spring Boot 应用程序中设置 h2

[英]Setup h2 in spring boot application with r2dbc and flyway

I'm playing around with Spring Boot and the reactive jdbc driver called r2dbc.我正在玩 Spring Boot 和称为 r2dbc 的反应式 jdbc 驱动程序。 In my main application I'm using Postgres as a database and now I want to the use h2 for the tests.在我的主应用程序中,我使用 Postgres 作为数据库,现在我想使用 h2 进行测试。 And the Flyway migration is working with the setup but when the Spring application is able to insert records. Flyway 迁移正在与设置一起工作,但是当 Spring 应用程序能够插入记录时。

Here is my setup and code这是我的设置和代码

@SpringBootTest
class CustomerRepositoryTest {

    @Autowired
    CustomerRepository repository;

    @Test
    void insertToDatabase() {
        repository.saveAll(List.of(new Customer("Jack", "Bauer"),
                new Customer("Chloe", "O'Brian"),
                new Customer("Kim", "Bauer"),
                new Customer("David", "Palmer"),
                new Customer("Michelle", "Dessler")))
                .blockLast(Duration.ofSeconds(10));
    }
}

Here is the error that I'm getting这是我得到的错误

 :: Spring Boot ::        (v2.3.4.RELEASE)

2020-10-14 15:59:18.538  INFO 25279 --- [           main] i.g.i.repository.CustomerRepositoryTest  : Starting CustomerRepositoryTest on imalik8088.fritz.box with PID 25279 (started by imalik in /Users/imalik/code/private/explore-java/spring-example)
2020-10-14 15:59:18.540  INFO 25279 --- [           main] i.g.i.repository.CustomerRepositoryTest  : No active profile set, falling back to default profiles: default
2020-10-14 15:59:19.108  INFO 25279 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2020-10-14 15:59:19.273  INFO 25279 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 160ms. Found 1 R2DBC repository interfaces.
2020-10-14 15:59:19.894  INFO 25279 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 6.5.0 by Redgate
2020-10-14 15:59:20.052  INFO 25279 --- [           main] o.f.c.internal.database.DatabaseFactory  : Database: jdbc:h2:mem:///DBNAME (H2 1.4)
2020-10-14 15:59:20.118  INFO 25279 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.022s)
2020-10-14 15:59:20.131  INFO 25279 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "PUBLIC"."flyway_schema_history" ...
2020-10-14 15:59:20.175  INFO 25279 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "PUBLIC": << Empty Schema >>
2020-10-14 15:59:20.178  INFO 25279 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "PUBLIC" to version 1.0.0 - schma
2020-10-14 15:59:20.204  INFO 25279 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "PUBLIC" (execution time 00:00.036s)
2020-10-14 15:59:20.689  INFO 25279 --- [           main] i.g.i.repository.CustomerRepositoryTest  : Started CustomerRepositoryTest in 2.466 seconds (JVM running for 3.326)

2020-10-14 15:59:21.115 DEBUG 25279 --- [           main] o.s.d.r2dbc.core.DefaultDatabaseClient   : Executing SQL statement [INSERT INTO customer (first_name, last_name) VALUES ($1, $2)]


org.springframework.data.r2dbc.BadSqlGrammarException: executeMany; bad SQL grammar [INSERT INTO customer (first_name, last_name) VALUES ($1, $2)]; nested exception is io.r2dbc.spi.R2dbcBadGrammarException: [42102] [42S02] Tabelle "CUSTOMER" nicht gefunden
Table "CUSTOMER" not found; SQL statement:
INSERT INTO customer (first_name, last_name) VALUES ($1, $2) [42102-200]

My src/test/resources/application.yaml is looking like this:我的 src/test/resources/application.yaml 看起来像这样:

spring:
  r2dbc:
    url: r2dbc:h2:mem:///DBNAME?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:

  flyway:
    url: jdbc:h2:mem:///DBNAME
    baseline-on-migrate: true
    user: sa
    password:

Any ideas whats missing missing or whats wrong with the setup?任何想法缺少什么或设置有什么问题? If further information is needed please let me know.如果需要更多信息,请告诉我。

Addition/Solution:添加/解决方案:

The url pattern is different between jdbc and r2dbc. jdbc 和 r2dbc 的 url 模式不同。 The working solution for me is as follows:我的工作解决方案如下:

url: r2dbc:h2:file:///./tmp/test-database
url: jdbc:h2:file:./tmp/test-database

And In order to setup Flyway you have to Configure Flyway:为了设置 Flyway,您必须配置 Flyway:

// Flyway is not compatible with r2dbc yet, therefore this config class is created
@Configuration
public class FlywayConfig {

    private final Environment env;

    public FlywayConfig(final Environment env) {
        this.env = env;
    }

    @Bean(initMethod = "migrate")
    public Flyway flyway() {
        return new Flyway(Flyway.configure()
                .baselineOnMigrate(true)
                .dataSource(
                        env.getRequiredProperty("spring.flyway.url"),
                        env.getRequiredProperty("spring.flyway.user"),
                        env.getRequiredProperty("spring.flyway.password"))
        );
    }
}

I've faced the same issue to setup and access to h2 database in memory for tests:我在设置和访问内存中的 h2 数据库以进行测试时遇到了同样的问题:

  • Liquibase for database migration using JDBC driver使用JDBC驱动程序进行数据库迁移的 Liquibase
  • Tests Reactive Crud Repository using R2DBC driver使用R2DBC驱动程序测试 Reactive Crud Repository

Error encoutred:出现错误:

org.springframework.data.r2dbc.BadSqlGrammarException: executeMany; org.springframework.data.r2dbc.BadSqlGrammarException: executeMany; bad SQL grammar [INSERT INTO MY_TABLE... Table "MY_TABLE" not found ...错误的 SQL 语法 [INSERT INTO MY_TABLE... 未找到表“MY_TABLE”...

Inspired by Chris's solution, i configured my src/testresources/application.properties file as follow:受 Chris 解决方案的启发,我将src/testresources/application.properties文件配置如下:

spring.r2dbc.url=r2dbc:h2:mem:///~/db/testdb
spring.r2dbc.username=sa
spring.r2dbc.password=

spring.liquibase.url=jdbc:h2:mem:~/db/testdb;DB_CLOSE_DELAY=-1
spring.liquibase.user=sa
spring.liquibase.password=
spring.liquibase.enabled=true

I am currently having the same problem using r2dbc with liquibase.我目前在使用 r2dbc 和 liquibase 时遇到了同样的问题。 I am suspecting that the JDBC url points to a different database due to a slightly different syntax between R2DB and JDBC.由于 R2DB 和 JDBC 之间的语法略有不同,我怀疑 JDBC url 指向不同的数据库。 I can manage to get h2 running from the file system though...我可以设法让 h2 从文件系统运行...

    url: r2dbc:h2:file:///~/db/testdb
...
    url: jdbc:h2:file:~/db/testdb

EDIT :编辑

In non-reactive Spring Data I'd usually populate the Schema into the H2 memory database using a schema.sql/data.sql pair.在非反应式 Spring Data 中,我通常使用 schema.sql/data.sql 对将 Schema 填充到 H2 内存数据库中。 This is also possible with R2DBC, but you have to configure the populator yourself.这也可以使用 R2DBC,但您必须自己配置填充器。

It's also in the Getting Started R2DBC Tutorial .它也在R2DBC 入门教程中 Basically you have to register a ConnectionFactoryInitializer bean.基本上你必须注册一个 ConnectionFactoryInitializer bean。

  @Bean
  public ConnectionFactoryInitializer initializer(@Qualifier("connectionFactory") ConnectionFactory connectionFactory) {
    var initializer = new ConnectionFactoryInitializer();
    initializer.setConnectionFactory(connectionFactory);

    var populator = new CompositeDatabasePopulator();
    populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql")));
    populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("data.sql")));
    initializer.setDatabasePopulator(populator);

    return initializer;
  }

Flyway currently only supports the blocking JDBC APIs, and it is not compatible with the reactive r2dbc if possbile do not mix them in the same application. Flyway 目前只支持阻塞的 JDBC API,如果 possbile 不将它们混合在同一个应用程序中,它与反应式 r2dbc 不兼容。

  1. Try to register a ConnectionFactoryInitializer to initiate the database schema and data as @Chris posted, my working example can be found here.尝试注册一个ConnectionFactoryInitializer以启动@Chris 发布的数据库架构和数据, 我的工作示例可以在这里找到。

  2. Try nkonev/r2dbc-migrate which is trying to migrate the flyway to the R2dbc world.尝试nkonev/r2dbc-migrate ,它试图将飞行路径迁移到 R2dbc 世界。

I was able to get it working.我能够让它工作。

First of all I created following test configuration class (because I want to execute tests only agains H2, on production mode I am using PostgreSQL):首先,我创建了以下测试配置类(因为我只想对 H2 执行测试,在生产模式下我使用的是 PostgreSQL):

@TestConfiguration
public class TestConfig {
    @Bean
    @Profile("test")
    public ConnectionFactory connectionFactory() {
        System.out.println(">>>>>>>>>> Using H2 in mem R2DBC connection factory");
        return H2ConnectionFactory.inMemory("testdb");
    }

    @Bean(initMethod = "migrate")
    @Profile("test")
    public Flyway flyway() {
        System.out.println("####### Using H2 in mem Flyway connection");
        return new Flyway(Flyway.configure()
                .baselineOnMigrate(true)
                .dataSource(
                        "jdbc:h2:mem:testdb",
                        "sa",
                        "")
        );
    }
}

As you can see in the code above, both beans are scoped to the "test" profile only.正如您在上面的代码中看到的,两个 bean 的范围都仅限于“test”配置文件。 As you can imagine I have pretty much the same beans in a regular ApplicationConfiguration class but annotated as a @Profile("default") and configured to use a PostgreSQL.正如您可以想象的那样,我在常规 ApplicationConfiguration 类中有几乎相同的 bean,但注释为@Profile("default")并配置为使用 PostgreSQL。

Second thing is that I created annotation which combines several other annotations to not repeat myself and to easily pickup beans declared in the TestConfig class:第二件事是我创建了一个注解,它结合了其他几个注解,以免重复我自己,并轻松获取在TestConfig类中声明的 bean:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootTest
@ActiveProfiles("test")
@Import(TestConfig.class)
public @interface IntegrationTest {
}

Now the test itself:现在测试本身:

@IntegrationTest
class CartsIntegrationTest {
 // test methods here ....
}

I believe the main hint is to use H2ConnectionFactory.inMemory("testdb");我相信主要提示是使用H2ConnectionFactory.inMemory("testdb");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用 WebFlux 启动 Spring 中的 H2 和 R2DBC 未找到列错误 - Column Not Found Error with H2 and R2DBC in Spring Boot with WebFlux 无法在使用 WebFlux 的 Spring 引导中使用 H2 和 R2DBC 创建 ConnectionFactory 错误 - Unable to create a ConnectionFactory Error with H2 and R2DBC in Spring Boot with WebFlux Postgres spring boot R2dbc 应用程序中缺少 DatabaseClient - Missing DatabaseClient in Postgres spring boot R2dbc application Spring、H2、R2DBC 和 Liquibase:/.testdb.trace.db:只读文件系统 - Spring, H2, R2DBC and Liquibase: /.testdb.trace.db: Read-only file system R2dbc 无法使用 tcp 与 h2 数据库一起使用 - R2dbc not working with h2 database using tcp 使用H2数据库和Flyway进行Spring Boot应用测试失败 - Spring Boot Application Tests with H2 Database and Flyway Fails to Seed Java 16 上 Spring R2DBC 应用程序的 Spring Boot Docker Native 映像在不受支持的方法上失败 - Spring Boot Docker Native image of Spring R2DBC application on Java 16 fails on unsupported methdod Spring 引导 R2DBC 无法在 MariaDB 中存储字符字段 - Spring Boot R2DBC fails to store character field in MariaDB Spring 引导数据 r2dbc 自动创建表 - Spring boot data r2dbc auto create tables 带有 MySQL 的 Spring Boot R2DBC - 异常:找不到表 - Spring Boot R2DBC with MySQL - Exception: Table not found
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM