当前位置: 首页 > 知识库问答 >
问题:

使用Flyway和Spring Boot迁移具有不同生命周期的多个模式

梁建德
2023-03-14

Flyway FAQ将多个模式分为三种情况:

  1. 多个相同的模式
  2. 模式是不同的,但有相同的生命周期
  3. 模式有一个独特的生命周期,或者必须是独立的和干净的分离

我们正在使用Maven构建一个多模块SpringBoot4.5.9项目。每个模块都是完全独立的,并且有自己的数据库模式。所有模式都驻留在一个数据库中,因此只有一个Spring数据源。

由于模块是独立的,我们希望分别管理它们各自的模式迁移,因此上面的选项(3)是最合适的。

然而,我找不到一种方法来配置Spring Boot的Flyway集成,就像Flyway常见问题解答建议的那样:

使用多个Flyway实例。每个实例管理自己的模式并引用自己的模式历史表。将每个架构的迁移放在不同的位置。

理想情况下,每个模块都有自己的数据库/迁移文件夹,其中包含自己的迁移SQL脚本。每个模块脚本的版本应该独立于其他模块中的脚本版本,每个模块的迁移历史应该存储在该模块架构中的表中。

如果我将迁移脚本放在每个模块的resources/db/migration文件夹中,flyway会检测到它们,但随后会抱怨:

org.flywaydb.core.api.FlywayException: Found more than one migration with version 0

有人知道如何完成所需的设置吗?

附言:所有这些的最终目标是能够(有一天,当系统扩展时)将这些模块拉到单独的服务中,而无需将数据库分解为多个部分。

共有2个答案

宋劲
2023-03-14

对于在同一数据库上有多个具有自己迁移历史记录的模块的情况,我找到了一个相当简单的解决方案:在使用相同的数据源时,为每个模块配置不同的flyway迁移历史记录表。

不幸的是,您不能有多个FlywayMigrationStrategybean,因此我将maven模块分开的做法是:

1) 在我的每个模块中将Flyway的FluentBuilder实例配置为bean:

@Configuration
public class FlywayModuleAMigrationConfig {

    @Bean
    public FluentConfiguration moduleAFlywayMigrationConfig() {
        return Flyway.configure()
                .table("flyway-module-a-schema-history")
                .locations("db/migration/module/a");
    }
}

2) 在我的应用程序的主SpringBoot模块中有一个FlywayMigrationStrategy,为模块的所有构建器进行配置:

@Component
public class FlywayModuleMigrationStrategy implements FlywayMigrationStrategy {

    @Autowired
    private List<FluentConfiguration> migrations;

    @Override
    public void migrate(Flyway flyway) {
        this.migrations.forEach(mig -> mig.
                baselineOnMigrate(true).
                baselineVersion("0").
                dataSource(flyway.getConfiguration().getDataSource()).
                load().
                migrate());
    }
}

您需要BaselineOnMigrate,因为flyway会注意到其他模块的现有表,因此必须忽略这些表作为基线。设置baselineVersion为0使您能够从脚本V1开始。

鲁斯伯
2023-03-14

这是一个长度答案,有两种工作方法。

  • 基于约定的版本控制,无序执行

基于公约的方法

可以做到这一点的一种方法是遵循给每个模块分配版本号的约定,然后让所有模块迁移成为主要版本的次要版本。例如,假设您有以下模块结构。

  • config包含公共Spring Boot的模块配置从该模块继承的所有其他模块。这是应用程序所在的模块。yml将保留
  • user包含用户注册模块的模块,user取决于config
  • email模块包含用于在后台发送电子邮件的代码,email取决于config

用户模块将有一个db/迁移文件夹,其中包含以下文件。

  • V2.001__create_users_schema.sql
  • V2.002__create_account_tables.sql
  • V2.003__create_x_tables.sql

email模块将有一个db/migration文件夹,其中包含以下文件

  • V3。001创建电子邮件模式。sql

使用上述版本控制约定,您可以随时返回并添加新的特定于模块的迁移。例如,在应用上述迁移后,可以添加V2。004\u创建\u y\u表。sql和flyway将填充V2之间的迁移。003和V3。0001

您需要配置flyway以允许按订单进行迁移,否则将出现错误。在引导中,您可以设置。

spring:
  flyway:
    out-of-order: true

关键是每个模块的第一个迁移文件首先发出createschema语句,然后后续迁移在所有DDL语句或对象引用中包括模式名称。

例如V2。001创建用户模式。sql包含

CREATE SCHEMA users;

V2。002创建账户表。sql包含

CREATE TABLE users.login(
    username text
);

请注意,传递给创建表的名称是用户。登录,其中包括架构名称。

通过为每个模块使用单独的模式,将来将更容易将模块及其db模式提取到单独的二进制文件中。由于spring boot使用单个数据库连接池,因此必须有1个数据库用户可以访问所有模块的模式。这需要警惕,以确保以下事情不会意外发生。

  • 编写引用多个架构的视图、查询和存储过程
  • 让一个模块将数据插入另一个模块的架构
  • 不同模块中的@Transactional方法相互调用。这是最容易搞砸的,因为模块通常会互相调用。您可以尝试通过两种方式解决此问题。选项1所有@Service类都受包保护,模块仅通过HTTP相互调用。选项2所有@Service类方法使用都需要新的传输传播@Transactional(传播=传播。需要\u new)。我认为,如果目标是最终提取到微服务体系结构,那么选项1会更好

这种方法适用于PostgreSQL,但不确定它是否适用于其他数据库,并且基于常见问题解答https://flywaydb.org/documentation/faq#hot-修复

多个Flyway实例

SpringBoot在执行迁移时查找类型为FlywayMigrationStrategy的bean。您可以实现这个界面,忽略应用级别迁移,并创建几个特定于模块的迁移,下面的代码可以工作。

import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
import org.springframework.stereotype.Component;

@Component
public class MultiModuleFlywayMigrationStrategy implements FlywayMigrationStrategy {


  @Override
  public void migrate(Flyway flyway) {
    var  dataSource = flyway.getConfiguration().getDataSource();
    Flyway testModule = Flyway.configure()
        .schemas("test")
        .locations("db/test")
        .dataSource(dataSource).load();

    Flyway ratingsModule = Flyway.configure()
        .schemas("rating")
        .locations("db/ratings")
        .dataSource(dataSource).load();

    // don't call flyway.migrate() since we don't want any migrations in db/migration
    testModule.migrate();
    ratingsModule.migrate();

  }
}

 类似资料:
  • 我有一个关于Flyway DB迁移的问题。如何管理处理同一数据库模式的多个项目(微服务)。如果每个项目中的Flyway移植脚本被其他项目修改,则不允许启动该脚本。他们是否有相关的文档或最佳实践?

  • 我认为留档(http://flywaydb.org/getstarted/existingDatabaseSetup.html)不够清楚,希望用一个例子来说明。我有一个给你: 假设我们有两个不同版本的生产数据库(1和2),其模式版本是隐式的,但通过查询现有表来确定。然后,我们将如何实现文档中描述的内容? 在我的例子中,两个版本都附加了一个脚本:版本1:创建表版本2:创建表 我已经创建了与版本1和版

  • 如何管理处理相同数据库模式的多个项目。如果被另一个项目修改,每个项目中的Flyway迁移脚本不允许启动。 例如: 我有一个带有FlywayInitializer类的spring boot项目X。 我有一个子模块Y,还有他自己的FlywayInitializer类 项目结构: 如何对项目X和Y使用与Flyway相同的schemaname“schema1”? 编辑:谢谢@jesper\u bk对我的帮

  • 我正在flyway的CMD中运行命令,但脚本文件的迁移会出现以下异常 [错误]无法执行目标组织。flywaydb:flyway maven插件:3.2.1:在convertopia auto db:org项目上迁移(默认cli)。flywaydb。果心应用程序编程接口。FlywayException:验证失败。迁移1.0.53的迁移描述不匹配[错误]- 我尝试过,它说构建成功,但问题仍然没有解决。

  • 我对Flyway完全陌生,但我正在尝试使用https://github.com/flyway/flyway-docker描述的docker-compose flyway mysql安排来迁移许多相同的测试数据库 据我所知,< code>migrate命令可以在它的< code>-schemas参数中接受多个模式,但是它似乎只将实际的SQL迁移应用于列表中的第一个模式。 例如,当我使用< code>

  • 我想使用 Flyway 获取特定数据库的最新架构版本值。Flyway 中是否有函数可以在命令行中获取当前架构版本号? 我可以运行以下命令: 这为我提供了数据库的整个架构内容(缩短),如下所示: 我只对最后一个架构条目版本“1.5.9”值感兴趣。 我的环境如下: < li>Windows 7 < li>Flyway 3.0