这是一个有两种可行方法的冗长答案。
基于约定的方法
可以做到这一点的一种方法是遵循为每个模块分配一个版本号的约定,然后让所有模块迁移成为主要版本的次要版本。例如假设您具有以下模块结构。
-
config 包含常见 Spring Boot 配置的模块,所有其他模块都从该模块继承。这是将保留 application.yml 的模块
-
user 包含用户注册模块的模块,user 依赖于config
-
email 包含后台发送邮件代码的模块,email 依赖于config
用户模块将有一个db/migration 文件夹,其中包含以下文件。
V2.001__create_users_schema.sql
V2.002__create_account_tables.sql
V2.003__create_x_tables.sql
email 模块将有一个 db/migration 文件夹,其中包含以下文件
V3.001__create_email_schema.sql
V3.002__create_outbox_table.sql
使用上述版本控制约定,您始终可以返回并添加新的模块特定迁移。例如,应用上述迁移后,您可以添加V2.004__create_y_table.sql,flyway 将填写V2.003 和V3.0001 之间的迁移
您需要配置 flyway 以允许外订单迁移,否则您将收到错误消息。在开机时可以设置。
spring:
flyway:
out-of-order: true
关键是每个模块的第一个迁移文件首先发出 CREATE SCHEMA 语句,然后后续迁移在所有 DDL 语句或对象引用中包含架构名称。
例如V2.001__create_users_schema.sql包含
CREATE SCHEMA users;
和V2.002__create_account_tables.sql 包含
CREATE TABLE users.login(
username text
);
请注意,传递给CREATE TABLE 的名称是users.login,其中包括架构名称。
通过为每个模块使用单独的架构,将来可以更轻松地将模块及其数据库架构提取到单独的二进制文件中。由于 spring boot 使用单个数据库连接池,因此您必须有 1 个数据库用户可以访问所有模块的模式。这需要保持警惕,以确保不会意外发生以下事情。
- 编写引用多个架构的视图、查询、存储过程
- 让一个模块将数据插入另一个模块的架构中
- 有
@Transactional不同模块中的方法相互调用。这是最容易搞砸的,因为模块通常会相互调用。您可以尝试通过两种方式解决此问题。 选项 1 所有@Service 类都受包保护,模块仅通过 HTTP 相互调用。 选项 2 使用的所有 @Service 类方法都需要新的传输传播 @Transactional(propagation = Propagation.REQUIRES_NEW)。如果目标是最终提取到微服务架构,我认为选项 1 更好。
这种方法适用于 PostgreSQL,不确定它与其他数据库的效果如何,并且基于常见问题解答 https://flywaydb.org/documentation/faq#hot-fixes
多个 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();
}
}