使用 R2DBC 进行数据库迁移

Posted

技术标签:

【中文标题】使用 R2DBC 进行数据库迁移【英文标题】:Database migrations with R2DBC 【发布时间】:2019-12-02 14:56:10 【问题描述】:

我是 R2DBC 的新手 (https://r2dbc.io/)。我想知道r2dbc的生态是否有数据库迁移工具/框架。

似乎 Liquibase 和 Flyway 依赖于 JDBC。是否有计划允许这些框架支持 r2dbc 驱动程序?

欢迎任何意见或反馈。

【问题讨论】:

这里可以查看已将 Flyway 集成到 R2DBC 项目中的项目:github.com/CrBatista/R2DBC-Example 【参考方案1】:

在我看来(粗略地浏览一下 R2DBC 网页的首页),R2DBC 的目标与迁移没有任何关系。该页面列出的主要功能如下:

反应式流 - R2DBC 建立在反应式流之上,提供完全反应式非阻塞 API。 关系型数据库 - R2DBC 使用响应式 API 使用 SQL 数据库,而 JDBC 的阻塞特性无法做到这一点。 可扩展的解决方案 - 反应式流可以从经典的每个连接一个线程的方法转变为更强大、更具可扩展性的方法。

其中没有任何东西可以保证将 R2DBC 支持添加到像 Liquibase 这样的框架中。当前使用的 JDBC 驱动程序不会因使用非阻塞 API 而受到影响,实际上并不需要“反应式 API”,而且几乎可以肯定每个连接不需要多个线程。

迁移工具主要关注数据库的形状/结构而不是内容,而 R2DBC 则针对主要关注实际数据的应用程序。

总之,我看不出有人为什么不使用像 Liquibase 这样使用 JDBC 的迁移工具,只是因为他们的应用程序使用 R2DBC,而且我认为将 R2DBC 支持添加到像这样的工具没有任何好处液化石油气。

【讨论】:

我明白了。您关于不需要 r2dbc 的数据迁移的结论是有道理的。感谢您的意见!【参考方案2】:

Steve 的回答是正确的,因为 R2DBC 主要是关于与实际数据的交互。我想补充一个不同的观点。

在迁移过程中,反应式 API 确实没有提供任何改进。事实上,仔细观察,迁移是启动过程的一部分,通常是同步的,至少在某种程度上是同步的。

要求 JDBC 进行迁移会增加这种应用程序安排的复杂性。您需要在现有 R2DBC 设置中包含 JDBC 驱动程序,并且需要配置另一个数据库连接,该连接指向与 R2DBC 相同的数据库。这两个要求都容易出错,因为它们需要配置为执行完全相同的操作。

如今,应用程序配置框架(Spring Boot、Micronaut、Quarkus)会在类路径中提供某个库时激活功能。配置 JDBC 驱动程序会启动应用程序不需要但在启动期间需要的启动功能,这有点浪费资源。

理想情况下,您配置一个单一的数据库连接技术,该技术可重复用于架构迁移和应用程序中的后续数据交互。

因此,要求 Liquibase 和 Flyway 提供基于 R2DBC 的集成是有意义的。

【讨论】:

非常感谢您的详细回复和提供的链接! 好视角。对于与我合作的大多数客户,他们已经在他们的应用程序和数据库迁移中使用了不同的技术——但 Datical 服务于可能无法反映大多数应用程序的市场部分。由于 Liquibase 和 Flyway 都是开源的,所以当用户实现它时,它们可能会支持 R2DBC。这两种产品现在都由营利性公司(分别为 Datical 和 Red Gate)提供支持,因此他们可以添加这种支持,但同样只有当他们的客户开始要求并支付时。 最近在 Flyway github 上打开了一个问题,该问题建议依赖 r2dbc 进行迁移。见这里:github.com/flyway/flyway/issues/2502。随意支持这个问题。感谢 Tomasz Kubacki!【参考方案3】:

以上两个答案都是正确的 - 只是想补充一点,如果您正在寻找快速简便的路径并且您正在使用 maven,那么 Flyway 可能是最方便的操作方式。

您只需要 Flyway Maven 插件、两个 pom 依赖项和迁移 sql 脚本。

例如。假设 spring - r2dbc - postgresql 只需三个简单的步骤即可准备好迁移基础架构:

(1) 向资源添加迁移脚本:

resources/db/migration/V1_init.sql

(2)给pom添加两个依赖

    <dependency>
        <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
    </dependency>

(3) 和构建部分的一个插件定义:

    <plugin>
        <groupId>org.flywaydb</groupId>
           <artifactId>flyway-maven-plugin</artifactId>
           <version>6.0.0-beta2</version>
    </plugin>

现在您有一个要迁移的 maven CLI 命令:

    mvn flyway:migrate -Dflyway.url=jdbc:postgresql://localhost:5432/test -Dflyway.user=test -Dflyway.password=test

查看更多 Flyway maven 插件文档here

【讨论】:

【参考方案4】:

如果有人遇到同样的问题并且不想使用maven-flyway-plugin,请查看FlywayAutoConfiguration 类。它有@Conditional(FlywayDataSourceCondition.class),里面有@ConditionalOnBean(DataSource.class)。因此,底线是您应该提供一个非反应式数据库环境以使 Flyway 工作。最直接的解决方案是这样做:

@Configuration
public class DataBaseConfig extends AbstractR2dbcConfiguration 

    @Value("$spring.data.postgres.host")
    private String host;
    @Value("$spring.data.postgres.port")
    private int port;
    @Value("$spring.data.postgres.database")
    private String database;
    @Value("$spring.data.postgres.username")
    private String username;
    @Value("$spring.data.postgres.password")
    private String password;

    @Bean
    public DatabaseClient databaseClient() 
        return DatabaseClient.create(connectionFactory());
    

    @Bean
    @Override
    public PostgresqlConnectionFactory connectionFactory() 
        PostgresqlConnectionConfiguration config = PostgresqlConnectionConfiguration.builder()
                .host(host)
                .port(port)
                .database(database)
                .username(username)
                .password(password)
                .build();
        return new PostgresqlConnectionFactory(config);
    

    @Bean
    public DataSource dataSource() 
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.driverClassName("org.postgresql.Driver");
        dataSourceBuilder.url("jdbc:postgresql://" + host + ":" + port + "/" + database);
        dataSourceBuilder.username(username);
        dataSourceBuilder.password(password);
        return dataSourceBuilder.build();
    

我这样做是因为我不想这样做: 1)每次启动时运行插件; 2) 在命令行中传递数据库属性

【讨论】:

【参考方案5】:

你可以试试我的包r2dbc-migrate。

在最小配置中(假设您使用的是 Spring Boot 2.3.0.M3),只需添加

<dependency>
  <groupId>name.nkonev.r2dbc-migrate</groupId>
  <artifactId>r2dbc-migrate-spring-boot-starter</artifactId>
  <version>0.0.24</version>
</dependency>

到 pom.xml

然后在类路径中添加 .sql 文件,例如在/db/migration/

然后添加

r2dbc.migrate.resourcesPath: classpath:/db/migration/*.sql

到你的 application.yml

【讨论】:

您发布了一个推广您的存储库/博客/产品的答案,这基本上是仅链接的。这通常被认为是垃圾邮件。请参阅:What signifies "Good" self promotion?、Some tips and advice about self-promotion、What is the exact definition of "spam" for Stack Overflow? 和 What makes something spam? 这个解决方案是一个很好的“临时解决方案”。对我来说,工作很棒。非常感谢@Nikita Nonev【参考方案6】:

拜托,最终有一个解决方案,至少是一个临时解决方案,因为目前还没有 Flyway 官方解决方案(我相信很快我们就会看到正式版本)。

请查看我的帖子:https://***.com/a/62864838/7681696

【讨论】:

以上是关于使用 R2DBC 进行数据库迁移的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Boot 的多个 R2DBC 数据源

使用反应式关系数据库连接规范R2DBC操作MySQL数据库

【MongoDB-数据迁移】

当还涉及迁移时,如何使用 django 进行同步数据库

使用 Spring 进行数据迁移

phinx:php数据库迁移