简体   繁体   English

Spring Boot + Hibernate + Flyway:不要在新数据库上运行迁移

[英]Spring Boot + Hibernate + Flyway: don't run migrations on new database

I'm using Flyway to update the DB schema.我正在使用 Flyway 更新数据库架构。 Currently, the latest version of the schema is 3 (the latest migration file is named V3__postgres.sql ).目前,schema 的最新版本为 3(最新的迁移文件名为V3__postgres.sql )。

If I run the application on a database which has an older schema version, Flyway executes the update scripts as expected.如果我在具有较旧架构版本的数据库上运行应用程序,Flyway 会按预期执行更新脚本。 However, if I run the app on a new (empty) database, flyway tries to execute the update scripts, but it doesn't find any tables (because Hibernate didn't create them yet), and the app terminates on error.但是,如果我在新的(空)数据库上运行应用程序,flyway 会尝试执行更新脚本,但它找不到任何表(因为 Hibernate 尚未创建它们),并且应用程序会因错误而终止。

I would like Flyway to not execute the update scripts on an empty database, since when Hibernate creates the tables, they will be at the latest version anyway.我希望 Flyway不在空数据库上执行更新脚本,因为当 Hibernate 创建表时,它们无论如何都将处于最新版本。

If I understand it correctly, I should be able to use parameter flyway.baseline-version for this.如果我理解正确,我应该能够为此使用参数flyway.baseline-version My theory is that if Flyway doesn't find table schema_version , it should create it and insert a record saying that the DB is at version 3. But even if I set flyway.baseline-version=3 , Flyway executes the scripts anyway.我的理论是,如果schema_version没有找到表schema_version ,它应该创建它并插入一条记录,说明数据库处于版本 3。但即使我设置了flyway.baseline-version=3flyway.baseline-version=3仍然会执行脚本。 I also tried to set parameter flyway.baseline-on-migrate=true and their different combinations but I couldn't get it to work.我还尝试设置参数flyway.baseline-on-migrate=true及其不同的组合,但我无法让它工作。

Do I understand the baseline-version parameter correctly or am I missing something?我是否正确理解了baseline-version参数,还是我遗漏了什么?

Note: I'm aware that since Spring Boot 2 the parameter namespace has changed to spring.flyway.* , but I'm using Spring Boot 1 so that is not the problem.注意:我知道自 Spring Boot 2 以来,参数命名空间已更改为spring.flyway.* ,但我使用的是 Spring Boot 1,所以这不是问题。

Solved: I created a custom FlywayMigrationStrategy bean where I manually check if Flyway has been already introduced to the database (by checking if the migration table exists).已解决:我创建了一个自定义FlywayMigrationStrategy bean,我在其中手动检查FlywayMigrationStrategy是否已引入数据库(通过检查迁移表是否存在)。 If not, I run the baseline command.如果没有,我运行baseline命令。 Then I call the migrate command as usual.然后我像往常一样调用migrate命令。

Here is the Spring Boot configuration:这是 Spring Boot 配置:

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FlywayConfig {

    @Autowired
    private DataSource dataSource;

    @Value("${flyway.table}")
    private String flywayTableName;

    @Value("${flyway.baselineVersionAsString}")
    private String baselineVersion;

    @Bean
    public FlywayMigrationStrategy flywayMigrationStrategy() {
        return flyway -> {
            if (!isFlywayInitialized()) {
                flyway.setBaselineVersionAsString(baselineVersion);
                flyway.baseline();
            }
            flyway.migrate();
        };
    }

    private boolean isFlywayInitialized() {

        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metadata = connection.getMetaData();
            ResultSet result = metadata.getTables(null, null, flywayTableName, null);
            return result.next();
        } catch (SQLException e) {
            throw new RuntimeException("Failed to check if Flyway is initialized", e);
        }
    }

}

As comments already mentioned, flyway and hibernate should not be used together to update the schema, but this does not mean that you can't use Hibernate at all to help you maintaining your schema.正如已经提到的评论,不应同时使用 flyway 和 hibernate 来更新架构,但这并不意味着您根本不能使用 Hibernate 来帮助您维护架构。

Baseline : This feature is definitely not designed to prevent migration execution on empty databases.基线:此功能绝对不是为了防止在空数据库上执行迁移。 This should be rather used when your database already exists (ie it has already tables and data, and you want to keep those data).当您的数据库已经存在(即它已经有表和数据,并且您想保留这些数据)时,应该使用它。 For empty databases it is useless.对于空数据库,它是无用的。

Example: Suppose you have an existing database, generated with 2 scripts:示例:假设您有一个现有数据库,由 2 个脚本生成:

V1__create_tables.sql
V2__create_constraints.sql

Now you want to manage further schema updates with flyway:现在你想用 flyway 管理进一步的模式更新:

V3__First_update.sql
V4__Second_update.sql

V2 is your baseline, meaning that migration of database will not execute migrations V1 and V2, because they already exist. V2 是您的基线,这意味着迁移数据库不会执行迁移 V1 和 V2,因为它们已经存在。

If you want to combine Spring Boot + Hibernate + Flyway :如果你想结合Spring Boot + Hibernate + Flyway

  • Disable automatic schema update by hibernate - as already mentioned, this might be dangerous (hbm2ddl.auto=false)通过休眠禁用自动模式更新 - 如前所述,这可能很危险(hbm2ddl.auto=false)
  • Use Hibernate SchemaGenerator to generate a big SQL-file, let's call it V1__initial_schema.sql , like in this old-but-still-valid article .使用 Hibernate SchemaGenerator 生成一个大的 SQL 文件,我们称之为V1__initial_schema.sql ,就像在这篇旧但仍然有效的文章中一样
  • If you happen to have a database in V1 with data you want to keep, you should baseline it .如果您在 V1 中碰巧有一个包含要保留的数据的数据库,则应该为其设置基线 Otherwise just start from an empty schema.否则,只需从空架构开始。 ( flyway clean ) and migrate ( flyway migrate ). ( flyway clean ) 和 migrate ( flyway migrate )。 WARNING: flyway clean will drop all your tables!警告: flyway clean会丢掉你所有的桌子!

Now you are ready to use both Hibernate and Flyway for each upcoming schema modification.现在,您已准备好对每个即将进行的模式修改同时使用 Hibernate 和 Flyway。 Let's suppose you have just updated your model:假设您刚刚更新了模型:

  • Use Hibernate SchemaGenerator to generate the same big SQL-file, let's call it generator-output.sql .使用 Hibernate SchemaGenerator 生成相同的大 SQL 文件,我们称之为generator-output.sql
  • Do a side-by-side comparison of V1__initial_schema.sql and generator-output.sql .V1__initial_schema.sqlgenerator-output.sql进行并排比较。 This will help you identify the differences between the 2 files.这将帮助您识别这两个文件之间的差异。 Based on these differences, you can generate a new migration file, let's call it V2__update.sql .基于这些差异,您可以生成一个新的迁移文件,我们称之为V2__update.sql
  • Do a flyway migrate on your database(s).对您的数据库进行快速flyway migrate

By the way When I try a inserting new version, I have seen that case sensitive filenames are important.顺便说一句,当我尝试插入新版本时,我发现区分大小写的文件名很重要。 Also everytime remember set this property: spring.flyway.ignore-future-migrations=false I used V100__script.sql instead v100__script.sql另外每次记得设置这个属性: spring.flyway.ignore-future-migrations=false我用V100__script.sql而不是v100__script.sql

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM