Flyway spring boot + java,由hibernate创建的新本地数据库,但现在迁移尝试应用已经发生的迁移

Posted

技术标签:

【中文标题】Flyway spring boot + java,由hibernate创建的新本地数据库,但现在迁移尝试应用已经发生的迁移【英文标题】:Flyway spring boot + java, new local database created by hibernate but now migrate tries to apply migrations that already happened 【发布时间】:2021-05-25 00:19:17 【问题描述】:

我最初使用 hibernate 创建项目以像大多数人一样创建表,但随后我开始使用 flyway 进行数据库迁移。

问题是我删除了包括 db 在内的整个本地系统并尝试再次旋转它,但我遇到了休眠和飞行路径的冲突。

顺便说一下,我正在使用 java api。所以当我去本地重建数据库时我打开了 spring.jpa.hibernate.ddl-auto=$HIBERNATE_DDL:create 只是第一次运行,然后转过来验证

所以它构建了所有表,但是现在当我尝试启动应用程序时,它会尝试运行第一个迁移

ALTER TABLE public.auth ADD COLUMN resent boolean

这将导致启动时出错,因为该新列是由休眠添加的

Error Code : 0
Message    : ERROR: column "resent" of relation "auth" already exists
Location   : db/migration/V1__Add_Resent_To_Auth.sql (/Users/brian/code/slap/build/resources/main/db/migration/V1__Add_Resent_To_Auth.sql)
Line       : 1
Statement  : ALTER TABLE public.auth
    ADD COLUMN resent boolean

那么我如何告诉 flyway 当前版本是 V9 并且仅在此之后运行迁移。它不应该只是查看 flyway_schema_history 并查看版本 9 是最后一个条目,然后再运行迁移吗?我一定是错过了什么

我尝试在我的配置中这样做以首先设置基线版本

@Configuration
class FlyWay() 

    @Value("\$spring.datasource.url")
    lateinit var url: String

    @Value("\$spring.datasource.username")
    lateinit var username: String

    @Value("\$spring.datasource.password")
    lateinit var password: String

    @Bean
    fun migrate() 
        val flyway = Flyway.configure().baselineVersion("9.0").dataSource(url, username, password).load()
        flyway.migrate()
    

没有这样的运气,它仍然尝试运行 V1

我也尝试将它添加到 application.properties spring.flyway.baselineVersion=9.0 同样的错误

【问题讨论】:

【参考方案1】:

我理解的场景:

表已经存在 表的状态对应于版本“9.0” 应为本地测试数据库设置一次 Flyway 基线版本

通过命令行设置版本可能很有用,因为它只应用于测试数据库一次,然后将应用正常的迁移策略。

文档见:https://flywaydb.org/documentation/usage/commandline/baseline

在 macOS 上,可以使用 brew install flyway 安装 Flyway 命令行客户端。

说明

确保删除表 flyway_schema_history。使用您首选的 SQL 客户端:
   drop table flyway_schema_history;
然后使用 Flyway 命令行客户端设置基线版本(本示例使用 Postgres 数据库):
   flyway -user=stephan -password= -url=jdbc:postgresql://localhost:5432/stephan -baselineVersion="9.0" -locations="src/main/resources/db/migration" baseline
签入 SQL 客户端:
select version from flyway_schema_history ;

现在应该显示“9.0”。之后,Spring Boot 应用程序应该像往常一样运行。

测试

替代方案

对于喜欢使用 Maven 命令执行此操作的人:

如上所示删除表 flyway_schema_history 使用命令mvn flyway:baseline -Dflyway.baselineVersion="9.0" 设置基线版本

这需要在pom.xml 文件中进行一些配置,例如如果使用 Postgres 数据库:

<build>
    ...
    <plugins>
        ...
        <plugin>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-maven-plugin</artifactId>
            <version>7.1.1</version>
            <configuration>
                <url>jdbc:postgresql://localhost:5432/stephan</url>
                <user>stephan</user>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>org.postgresql</groupId>
                    <artifactId>postgresql</artifactId>
                    <version>42.2.18</version>
                </dependency>
            </dependencies>
        </plugin>
    ...

使用 Maven 进行测试

快速测试显示相同的结果。

【讨论】:

【参考方案2】:

为什么不从您的数据库(由 Hibernate 创建)导出 SQL 脚本并将其作为第一个 Flyway 脚本添加到您的应用程序中?这是最干净的解决方案,因为当应用程序将在其他系统上运行时,不需要再次手动启动 Hibernate。

【讨论】:

我想办法做到这一点,但找不到解决方案,我也无法在生产中搞乱数据 我没有读到有生产数据库。我仍然会采用这种方法并将基线属性专门用于生产。如果设置更容易,作为替代方案,在本地运行应用程序并将 flyway_schema_history 表(包含已执行脚本的条目)复制到生产环境,因此不需要基线。 基线属性不起作用,这就是问题所在,我需要告诉 flyway 它在版本 9 上的方式 我认为它应该是baselineVersionAsString 属性。但是我在网上找不到可靠的信息,所以也许复制历史记录表是一个更快的选择。【参考方案3】:

在您的 application.yml 中添加以下行后尝试一次 spring.flyway.baseline-on-migrate: true

【讨论】:

以上是关于Flyway spring boot + java,由hibernate创建的新本地数据库,但现在迁移尝试应用已经发生的迁移的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot + Flyway + AWS:原因:java.sql.SQLException:找不到合适的驱动程序

Spring Boot 2.1.0 和 Flyway 4.2.0

Flyway spring boot + java,由hibernate创建的新本地数据库,但现在迁移尝试应用已经发生的迁移

具有 JPA 依赖关系的 Flyway Spring Boot Autowired Bean

Spring Boot学习总结(27)—— Spring Boot中两个数据库迁移工具Liquibase和Flyway的比较

Spring Boot学习总结(27)—— Spring Boot中两个数据库迁移工具Liquibase和Flyway的比较