Несколько пролетов с FlywayMigrationStrategy - PullRequest
2 голосов
/ 03 апреля 2020

У меня есть несколько Flyway источников данных, и мне нужно реализовать FlywayMigrationStrategy для них. Каждый источник данных имеет свою собственную flyway_migration таблицу и c.

Но когда я создаю FlywayMigrationStrategy, он не будет вызван.

Это не работает:

@Bean
public FlywayMigrationStrategy cleanMigrateStrategy() { ...

Это работает:

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

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

    flyway.clean();
    flyway.migrate();
  }

Есть ли лучшие варианты?

1 Ответ

3 голосов
/ 03 апреля 2020

Почему вы реализуете метод @PostContruct? Как я вижу, FlywayMigrationStrategy - это функциональный интерфейс, и я думаю, что ваш код должен выглядеть следующим образом:

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

    return strategy;
}

Хорошо, у меня есть некоторые исследования, и теперь я могу объяснить ответ на ваш вопрос.

Прежде всего, давайте проверим FlywayAutoConfiguration

Когда вы используете настройку миграции пролета через файл свойств, конфигурация работает, создает и настраивает экземпляры Flyway и переносит базу. Все они настроены в FlywayConfiguration. Давайте посмотрим на аннотацию условия для конфигурации

@ConditionalOnMissingBean(Flyway.class)

Это означает, что конфигурация не создается, если бин для класса Flyway.class уже существует в контексте Spring. Хорошо, затем конфигурация создает только для 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());
}

Не так важно, как config конфигурирует bean-компонент flyway, но важно, чтобы он создавал FlywayMigrationInitializer, который инициирует миграцию. Как видите, FlywayMigrationStrategy имеет значение FlywayMigrationInitializer в качестве аргумента конструктора. И именно он использует MigrationStrategy, если он был установлен, в противном случае просто выполните flyway.migrate(). (см. исходный код)

Хорошо, теперь мы знаем, как это работает в целом, давайте посмотрим в вашем коде.

Вы создаете экземпляры flyway в своей основной конфигурации:

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

Поскольку вы уже создаете экземпляры Flyway, FlywayConfiguration не создается (из-за условия), и бины инициализатора для ваших бинов Flyway также не создаются. В результате миграции не выполняются, и вам нужно добавить (initMethod = "migrate") к объявлению компонента для начала миграции. Кроме того, я думаю, что @FlywayDataSource не требуется и ничего не делает.

Давайте теперь go для вашей тестовой конфигурации.

Когда вы создаете FlywayMigrationStrategy, он работает правильно, но никто не использует стратегию (в вашем основном конфигурационном файле вы называете Flyway.migrate, так как initMethod и MigrationInitializer не создаются). В результате стратегия не выполняется.

В вашем рабочем примере вы добавили вызов clean и мигрировали в методе TestConfiguration postconstruct. И это работает, потому что метод postconstruct выполняется после создания конфигурации. НО если вы отладите свой код, вы увидите, что метод migrate выполняется дважды для каждого экземпляра Flyway: в виде компонента initMethod и из метода постконтракта Testconfiguration. Я не уверен, что это то, что вам нужно.

Хорошо, для исправления я предлагаю удалить (initMethod = "migrate") и @FlywayDataSource, создать FlywayMigrationInitializer bean для каждого Flyway bean в вашей основной конфигурации и внедрите FlywayMigrationStrategy в свою тестовую конфигурацию.

@Bean
public FlywayMigrationInitializer flywayInitializer(@Qualifier(...) Flyway flyway,
        ObjectProvider<FlywayMigrationStrategy> migrationStrategy) {
        return new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...