9

I am new to R2DBC (https://r2dbc.io/). I would like to know whether r2dbc's ecosystem has a database migration tool/framework.

It seems Liquibase & Flyway depend on JDBC. Is there a plan for allowing those frameworks to support a r2dbc driver?

Any input or feedback welcome.

mp911de
  • 17,546
  • 2
  • 55
  • 95
balteo
  • 23,602
  • 63
  • 219
  • 412

6 Answers6

17

Steve's answer is correct hat R2DBC is primarily about interaction with the actual data. I'd like to add a different perspective.

It's true that a reactive API does not provide any improvement during migrations. In fact, looking closely, migrations are part of the startup process which is typically synchronous, at least synchronized to some extent.

Requiring JDBC for migration adds to complexity in such an application arrangement. You are required to include a JDBC driver to an existing R2DBC setup and you need to configure another database connection that points to the same database as with R2DBC. Both requirements are error-prone as they need to be configured to do the exact same thing.

Nowadays, application configuration frameworks (Spring Boot, Micronaut, Quarkus) activate functionality when a certain library is available from the classpath. Having a JDBC driver configured boots functionality that isn't required for the application but required during bootstrapping and that is sort of a waste of resources.

Ideally, you configure a single database connection technology that is reused for schema migration and for later data interaction within your application.

Therefore it makes sense to ask Liquibase and Flyway to provide an R2DBC-based integration.

mp911de
  • 17,546
  • 2
  • 55
  • 95
  • 1
    Thanks a lot for this detailed reply and the links provided! – balteo Jul 26 '19 at 10:55
  • Good perspective. For most of the clients that I work with, they already are using different technologies for their application vs. their database migrations - but Datical serves a segment of the market that may not be reflective of a majority of applications. Since both Liquibase and Flyway are open source, they will probably support R2DBC when the users implement it. Both products are now supported by for-profit companies (Datical and Red Gate, respectively) so they could add that support, but again only when their customers start asking and paying for it. – SteveDonie Jul 26 '19 at 19:00
  • 2
    An issue was recently opened on the Flyway github that proposes migrations relying on r2dbc. See here: https://github.com/flyway/flyway/issues/2502. Feel free to upvote this issue. Thanks to Tomasz Kubacki for that! – balteo Sep 25 '19 at 08:10
5

You can try my package r2dbc-migrate.

In minimal configuration (let's suppose that you are using Spring Boot 2.3.0.M3), just add

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

to pom.xml

then add .sql files in classpath, for example in /db/migration/

then add

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

to your application.yml

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Nikita Konev
  • 71
  • 1
  • 4
  • 1
    You posted an answer promoting your repository/blog/product which is basically link-only. That's usually considered spam. Please see: [What signifies "Good" self promotion?](https://meta.stackexchange.com/questions/182212), [Some tips and advice about self-promotion](https://stackoverflow.com/help/promotion), [What is the exact definition of "spam" for Stack Overflow?](https://meta.stackoverflow.com/questions/260638/), and [What makes something spam?](https://meta.stackexchange.com/a/58035/356669) – M-- Apr 03 '20 at 15:46
  • 1
    This solution is a excellent "temporary solution". For me, work wonderfully. Thanks a lot @Nikita Nonev – GtdDev Jul 12 '20 at 18:21
  • Also have to agree that this is a great solution. Quite frankly, this is a really big hole in the r2dbc world - anyone using flyway or liquibase won't have the ability to perform migrations after switching to webflux + r2dbc. This little package fills that need nicely. – teuber789 Apr 23 '22 at 19:12
3

It doesn't seem to me (from an admittedly cursory glance at the front page of the R2DBC web page) that the goals of R2DBC really have anything to do with migrations. That page lists key features as:

  • Reactive Streams - R2DBC is founded on Reactive Streams providing a fully reactive non-blocking API.
  • Relational Databases - R2DBC engages SQL databases with a reactive API, something not possible with the blocking nature of JDBC.
  • Scalable Solutions - Reactive Streams makes it possible to move from the classic one thread per connection approach to a more powerful, more scalable approach.

There is nothing in there that warrants adding R2DBC support to a framework like Liquibase. The JDBC drivers currently in use don't suffer from their use of a non-blocking API, don't really need a "reactive API", and almost certainly don't need to have more than one thread per connection.

Migration tools are primarily concerned with the shape/structure of the database and not the contents, while R2DBC is aimed at applications that primarily care about the actual data.

In Summary, I don't see any reason why someone wouldn't use a migration tool like Liquibase that uses JDBC just because their application uses R2DBC, and I don't see any advantage to adding R2DBC support to a tool like Liquibase.

SteveDonie
  • 8,700
  • 3
  • 43
  • 43
  • 2
    I see. Your conclusion about data migrations not requiring r2dbc makes sense. Thanks for your input! – balteo Jul 24 '19 at 13:51
  • It doesn't. But the point is, liquibase itegrates with spring, so while spring starts, it executes migration. Now, if my spring project uses R2DBC, then addition of JDBC just for migration doesn't make sense. – Akshay Mar 09 '22 at 14:07
1

If anyone face the same problem and doesn't want to use the maven-flyway-plugin, take a look at the FlywayAutoConfiguration class. It has @Conditional(FlywayDataSourceCondition.class), which has @ConditionalOnBean(DataSource.class) inside. Therefore the bottom line is you should provide a non-reactive database environment to make Flyway work. The most straight forward solution is to do something like this:

@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();
    }
}

I went this way as I didn't want to: 1) Run the plugin on each startup; 2) Pass database properties in the comand line

Ivan Timoshin
  • 601
  • 9
  • 23
0

Both answers above are correct - just wanted to add that if you are looking for fast and easy path and you are using maven then Flyway is probably the most convenient way to operate.

All you need to have is Flyway Maven plugin, two pom dependencies and migration sql scripts.

Eg. assuming spring - r2dbc - postgresql you can have migration infrastructure ready in just three simple steps:

(1) Add migration script to resources:

resources/db/migration/V1_init.sql

(2) add two dependencies to pom

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

(3) and one plugin definition in build section:

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

and now you have single maven CLI command to migrate:

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

See more Flyway maven plugin docs here

tomaszkubacki
  • 3,181
  • 3
  • 23
  • 36
0

Please, there is a solution for that finally, at least a temporary solution, because there is no Flyway official solution yet (I believe soon we are gonna see a official version).

Please check my post: https://stackoverflow.com/a/62864838/7681696

GtdDev
  • 748
  • 6
  • 14