多模块 Gradle 项目中的 Flyway 迁移(干净架构)
使用 Flyway 在 Java 中自动执行数据库迁移
数据库迁移是软件开发的一个重要方面,特别是在持续集成和交付 (CI/CD) 为标准实践的环境中。随着应用程序的增长和发展,它所依赖的数据库模式也必须如此。手动管理这些架构更改可能会导致错误并消耗大量时间。
Flyway 登场,这是一款专为简化数据库迁移而定制的宝贵开源工具。 Flyway 为您的数据库引入了版本控制,使您能够安全可靠地迁移架构。在本文中,我们将探索如何使用 Flyway 在多模块 gragle java 项目中自动化数据库迁移,确保管理数据库更改成为一个简化的、防错的过程。
有关飞行路线的更多详细信息
了解 Gradle 中的多项目构建
虽然一些较小的项目或整体应用程序可能仅使用一个构建文件和统一的源结构进行管理,但较大的项目经常被组织成多个相互依赖的模块。术语“相互依赖”是这里的关键,强调了通过单一构建过程连接这些模块的需要。
Gradle 以其多项目构建功能(通常称为多模块项目)来满足这种设置。在 Gradle 的术语中,这些模块称为子项目。
多项目构建是围绕一个根项目构建的,并且可以包含其下的多个子项目。
目录结构应如下所示:
├── .gradle │ └── ⋮ ├── gradle │ ├── libs.versions.toml │ └── wrapper ├── gradlew ├── gradlew.bat ├── settings.gradle.kts (1) ├── sub-project-1 │ └── build.gradle.kts (2) ├── sub-project-2 │ └── build.gradle.kts (2) └── sub-project-3 └── build.gradle.kts (2)
(1) settings.gradle.kts 文件应包含所有子项目。
(2) 每个子项目应该有自己的build.gradle.kts文件。
利用 Gradle 子模块实现简洁的架构
清洁架构是一种强调关注点分离的设计模式,使软件更易于维护和测试。在项目中实现此架构的实用方法之一是使用 Gradle 的子模块结构来组织代码库。以下是如何将 Clean Architecture 与 Gradle 子模块结合起来:
干净的架构层:
核心:
- 包含业务逻辑、领域模型和应用程序规则。 不依赖于外部或网络。
- 应尽可能独立于特定于框架的实现。
外部:
- 处理外部操作或集成,例如数据库迁移或第三方服务交互。
- 业务逻辑可能依赖于 Core,但不应依赖于 Web。
网页:
- 入口点,公开 REST API 并处理 HTTP 请求。
- 业务逻辑依赖于核心,集成可能依赖于外部。
├── .gradle │ └── ⋮ ├── gradle │ ├── libs.versions.toml │ └── wrapper ├── gradlew ├── gradlew.bat ├── settings.gradle.kts (1) ├── sub-project-1 │ └── build.gradle.kts (2) ├── sub-project-2 │ └── build.gradle.kts (2) └── sub-project-3 └── build.gradle.kts (2)
第 1 步: 创建一个基于 Java 的 Gradle 项目并将其命名为“SchoolStaff”。
第 2 步: 转到 Spring Initializr 并生成一个名为 Web.
的 REST API 项目第 3 步: 创建一个基于 Java 的 Gradle 项目并将其命名为 External.
第 4 步: 创建一个基于 Java 的 Gradle 项目并将其命名为 Core.
根目录 build.gradle.kts
SchoolStaff/ ├── Core/ │ ├── src/ │ │ └── main/ │ │ ├── java/ # Business logic and domain objects │ │ └── resources/ # Core-specific resources (if any) │ └── build.gradle.kts ├── External/ │ ├── src/ │ │ └── main/ │ │ ├── java/ # External integration code │ │ └── resources/ # db/migration and other external resources │ └── build.gradle.kts ├── Web/ │ ├── src/ │ │ └── main/ │ │ ├── java/ # REST controllers and entry-point logic │ │ └── resources/ # Application-specific configuration │ └── build.gradle.kts ├── build.gradle.kts # Root Gradle build └── settings.gradle.kts # Project module settings
settings.gradle.kts
plugins { id("java") } allprojects { group = "school.staff" version = "1.0.0" repositories { mavenLocal() mavenCentral() } } subprojects { apply(plugin = "java") dependencies { testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") } tasks.test { useJUnitPlatform() } }
“Web”项目所需的依赖项。
rootProject.name = "SchoolStaff" include("Core", "External", "Web")
“核心”项目所需的依赖项。
dependencies { implementation(project(":Core")) implementation(project(":External")) }
“外部”项目所需的依赖项。
dependencies { runtimeOnly(project(":External")) }
我们使用以下插件进行 Flyway 迁移:
import java.sql.DriverManager import java.util.Properties // Function to load properties based on the environment fun loadProperties(env: String): Properties { val properties = Properties() val propsFile = file("../web/src/main/resources/application-$env.properties") if (propsFile.exists()) { propsFile.inputStream().use { properties.load(it) } } else { throw GradleException("Properties file for environment '$env' not found: ${propsFile.absolutePath}") } return properties } // Set the environment (default is 'dev' if no argument is passed) val env = project.findProperty("env")?.toString() ?: "dev" // Load properties for the chosen environment val dbProps = loadProperties(env) buildscript { dependencies { classpath("org.flywaydb:flyway-database-postgresql:11.1.0") // This is required for the flyway plugin to work on the migration, otherwise it will throw an error as No Database found classpath("org.postgresql:postgresql:42.7.4") } } plugins { id("java-library") id("org.flywaydb.flyway") version "11.0.1" } group = "school.staff" version = "unspecified" repositories { mavenLocal() mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jpa:3.4.0") implementation("org.postgresql:postgresql:42.7.4") implementation("org.flywaydb:flyway-core:11.0.1") implementation("org.flywaydb:flyway-database-postgresql:11.0.1") implementation("org.flywaydb:flyway-gradle-plugin:11.0.1") implementation (project(":Core")) testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") } tasks.test { useJUnitPlatform() } // Task to create the database if it doesn't exist tasks.register("createDatabase") { doLast { val dbUrl = dbProps["spring.datasource.url"] as String val dbUsername = dbProps["spring.datasource.username"] as String val dbPassword = dbProps["spring.datasource.password"] as String // Extract the base URL and database name val baseDbUrl = dbUrl.substringBeforeLast("/")+ "/" val dbName = dbUrl.substringAfterLast("/") // Connect to the PostgreSQL server (without the specific database) DriverManager.getConnection(baseDbUrl, dbUsername, dbPassword).use { connection -> val stmt = connection.createStatement() val resultSet = stmt.executeQuery("SELECT 1 FROM pg_database WHERE datname = '$dbName'") if (!resultSet.next()) { println("Database '$dbName' does not exist. Creating it...") stmt.executeUpdate("CREATE DATABASE \"$dbName\"") println("Database '$dbName' created successfully.") } else { println("Database '$dbName' already exists.") } } } } flyway { url = dbProps["spring.datasource.url"] as String user = dbProps["spring.datasource.username"] as String password = dbProps["spring.datasource.password"] as String locations = arrayOf("classpath:db/migration") baselineOnMigrate = true } //Ensure classes are built before migration tasks.named("flywayMigrate").configure { dependsOn(tasks.named("createDatabase")) dependsOn(tasks.named("classes")) }
这种方法非常适合生产环境,因为它确保了受控且可靠的迁移。我们不会在每次应用程序启动时自动运行迁移,而是仅在必要时执行迁移,从而提供更大的灵活性和控制力。
我们还利用 Spring 应用程序中的 application.properties 文件来管理数据库连接和凭据。 BaselineOnMigrate = true 设置可确保将初始迁移用作未来迁移的基线。
plugins { id("org.flywaydb.flyway") version "11.0.1" }
我们可以使用 JPA Buddy 生成外部项目的 resources/db/migration 目录中的所有迁移文件。
V1__Initial_Migration
flyway { url = dbProps["spring.datasource.url"] as String user = dbProps["spring.datasource.username"] as String password = dbProps["spring.datasource.password"] as String locations = arrayOf("classpath:db/migration") baselineOnMigrate = true }
从根项目中,我们可以使用以下命令执行 Flyway 迁移:
CREATE TABLE _user ( id UUID NOT NULL, created_by UUID, created_date TIMESTAMP WITH TIME ZONE, last_modified_by UUID, last_modified_date TIMESTAMP WITH TIME ZONE, first_name VARCHAR(255), last_name VARCHAR(255), email VARCHAR(255), password VARCHAR(255), tenant_id UUID, CONSTRAINT pk__user PRIMARY KEY (id) );
这会将所有迁移文件应用到数据库。
结论
我们探索了如何在 Gradle 多模块项目中使用 Flyway 自动化数据库迁移,这对于在 CI/CD 环境中维护架构一致性至关重要。
我们还介绍了 Gradle 如何支持多项目构建,将复杂的项目组织成可管理的子项目,每个子项目都有自己的构建配置,统一在根构建脚本下。
最后,我们将 Clean Architecture 与 Gradle 模块结合起来,将项目构建为核心层、外部层和 Web 层,促进关注点和依赖管理的清晰分离。
这些实践增强了模块化、自动化和可维护性,为可扩展、无错误的软件开发奠定了基础。
以上是多模块 Gradle 项目中的 Flyway 迁移(干净架构)的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

公司安全软件导致部分应用无法正常运行的排查与解决方法许多公司为了保障内部网络安全,会部署安全软件。...

将姓名转换为数字以实现排序的解决方案在许多应用场景中,用户可能需要在群组中进行排序,尤其是在一个用...

系统对接中的字段映射处理在进行系统对接时,常常会遇到一个棘手的问题:如何将A系统的接口字段有效地映�...

在使用IntelliJIDEAUltimate版本启动Spring...

在使用MyBatis-Plus或其他ORM框架进行数据库操作时,经常需要根据实体类的属性名构造查询条件。如果每次都手动...

Java对象与数组的转换:深入探讨强制类型转换的风险与正确方法很多Java初学者会遇到将一个对象转换成数组的�...

电商平台SKU和SPU表设计详解本文将探讨电商平台中SKU和SPU的数据库设计问题,特别是如何处理用户自定义销售属...

Redis缓存方案如何实现产品排行榜列表的需求?在开发过程中,我们常常需要处理排行榜的需求,例如展示一个�...
