使用 FlywayMigrationStrategy 的多个 Flyways

Mih*_* L. 2 flyway spring-boot

我有多个Flyway数据源,需要实现FlywayMigrationStrategy它们。每个数据源都有自己的flyway_migration表等。

但是当我创建FlywayMigrationStrategy它时不会被调用。

这不起作用:

@Bean
public FlywayMigrationStrategy cleanMigrateStrategy() { ...
Run Code Online (Sandbox Code Playgroud)

这有效:

  @PostConstruct
  public void cleanBeforeMigrate(
      @Qualifier("dpaFlyway") Flyway dpaflyway,
      @Qualifier("flyway") Flyway flyway) {

    dpaflyway.clean();
    dpaflyway.migrate();

    flyway.clean();
    flyway.migrate();
  }
Run Code Online (Sandbox Code Playgroud)

有更好的选择吗?

Max*_*pov 6

你为什么要实现@PostContruct方法?如我所见,FlywayMigrationStrategy是一个功能接口,我猜你的代码应该是这样的:

@Bean
public FlywayMigrationStrategy cleanMigrateStrategy() {
    FlywayMigrationStrategy strategy = new FlywayMigrationStrategy() {
        @Override
        public void migrate(Flyway flyway) {
            flyway.clean();
            flyway.migrate();
        }
    };

    return strategy;
}
Run Code Online (Sandbox Code Playgroud)

好的,我有一些研究,现在可以解释您的问题的答案。

首先,让我们检查一下 FlywayAutoConfiguration

当您通过属性文件使用配置 flyway 迁移时,配置将起作用,创建和配置 Flyway 实例并迁移 base。所有这些都在FlywayConfiguration. 我们看一下配置上的条件注解

@ConditionalOnMissingBean(Flyway.class)
Run Code Online (Sandbox Code Playgroud)

这意味着如果Flyway.classspring 上下文中已经存在类的 bean,则不会创建配置。好的,接下来,配置只创建到bean

@Bean
public Flyway flyway(FlywayProperties properties, DataSourceProperties dataSourceProperties,
        ResourceLoader resourceLoader, ObjectProvider<DataSource> dataSource,
        @FlywayDataSource ObjectProvider<DataSource> flywayDataSource,
        ObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers,
        ObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks)
.....
@Bean
@ConditionalOnMissingBean
public FlywayMigrationInitializer flywayInitializer(Flyway flyway,
        ObjectProvider<FlywayMigrationStrategy> migrationStrategy) {
        return new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());
}
Run Code Online (Sandbox Code Playgroud)

配置如何配置flywaybean并不重要,但重要的是它创建了FlywayMigrationInitializer启动迁移的 。如您所见,FlywayMigrationStrategy被设置FlywayMigrationInitializer为构造函数参数。如果设置了 MigrationStrategy ,他就会使用它,否则就执行flyway.migrate()。(见源代码)

好的,现在我们知道它是如何工作的,让我们看看你的代码。

您在主配置中创建飞行路径实例:

@Bean(initMethod = "migrate")
@FlywayDataSource
public Flyway firstFlyway(DataSource dataSource) {
  return new Flyway(
      new FluentConfiguration()
          .locations("db/first-migration")
          .schemas("first")
          .outOfOrder(true)
          .dataSource(dataSource)
  );
}

@Bean(initMethod = "migrate")
@FlywayDataSource
public Flyway secondFlyway(@Qualifier("secondDataSource") DataSource dataSource) {
  return new Flyway(
      new FluentConfiguration()
          .dataSource(dataSource)
          .schemas("second")
          .outOfOrder(true)
          .locations("db/second-migration")
  );
}
Run Code Online (Sandbox Code Playgroud)

由于您已经创建了 Flyway 实例,FlywayConfiguration因此不会创建(由于条件)并且您的Flywaybean 的Initializer bean 也不会创建。因此不会执行迁移,您需要添加(initMethod = "migrate")到 bean 声明以开始迁移。另外,我认为这@FlywayDataSource不是必需的,什么也不做。

现在让我们进入您的测试配置。

当您创建时FlywayMigrationStrategy,它工作正常,但没有人使用该策略(在您的主配置文件中,您调用Flyway.migrateinitMethod 和 MigrationInitializer 未创建)。结果,该策略未执行。

在您的工作示例中,您在TestConfigurationpostconstruct 方法中添加了调用 clean 和 migrate 。它的工作原理是在创建配置后执行 postconstruct 方法。但是,如果您调试代码,您将看到该migrate方法为每个 Flyway 实例执行了两次:作为 beaninitMethod和来自 Testconfiguration postcontruct 方法。我不确定这是你想要的。

好的,为了修复它,我建议删除(initMethod = "migrate")@FlywayDataSource,为主配置中的FlywayMigrationInitializer每个Flywaybean创建bean并FlywayMigrationStrategy在您的测试配置中实现。

@Bean
public FlywayMigrationInitializer flywayInitializer(@Qualifier(...) Flyway flyway,
        ObjectProvider<FlywayMigrationStrategy> migrationStrategy) {
        return new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());
}
Run Code Online (Sandbox Code Playgroud)