[英]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=3
, flyway.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 :
V1__initial_schema.sql
, like in this old-but-still-valid article .V1__initial_schema.sql
,就像在这篇旧但仍然有效的文章中一样。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:
假设您刚刚更新了模型:
generator-output.sql
.generator-output.sql
。V1__initial_schema.sql
and generator-output.sql
.V1__initial_schema.sql
和generator-output.sql
进行并排比较。 This will help you identify the differences between the 2 files.V2__update.sql
.V2__update.sql
。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.