ホームページ > Java > &#&チュートリアル > マルチモジュール Gradle プロジェクトでの Flyway の移行 (クリーン アーキテクチャ)

マルチモジュール Gradle プロジェクトでの Flyway の移行 (クリーン アーキテクチャ)

Barbara Streisand
リリース: 2025-01-19 08:05:08
オリジナル
619 人が閲覧しました

Flyway を使用した Java でのデータベース移行の自動化

データベースの移行は、特に継続的インテグレーションとデリバリー (CI/CD) が標準的な実践である環境では、ソフトウェア開発の重要な側面です。アプリケーションが成長し、進化するにつれて、アプリケーションが依存するデータベース スキーマも変化する必要があります。これらのスキーマ変更を手動で管理すると、エラーが発生し、かなりの時間がかかる可能性があります。

データベースの移行を簡素化するために調整された貴重なオープンソース ツールである Flyway を紹介します。 Flyway はデータベースにバージョン管理を導入し、スキーマを安全かつ確実に移行できるようにします。この記事では、Flyway を使用してマルチモジュールの Gragle Java プロジェクトでデータベースの移行を自動化し、データベースの変更管理が合理化され、エラーが発生しにくいプロセスになるようにする方法を検討します。

フライウェイの詳細

Gradle でのマルチプロジェクト ビルドを理解する

一部の小規模なプロジェクトやモノリシック アプリケーションは、1 つのビルド ファイルと統一されたソース構造だけで管理できる場合がありますが、大規模なプロジェクトは、相互依存する複数のモジュールに編成されることがよくあります。ここでは「相互依存」という用語が重要であり、単一のビルド プロセスを介してこれらのモジュールを接続する必要性を強調しています。

Gradle は、マルチモジュール プロジェクトと呼ばれることが多いマルチプロジェクト ビルド機能を使用して、このセットアップに対応します。 Gradle の用語では、これらのモジュールはサブプロジェクトと呼ばれます。

マルチプロジェクト ビルドは 1 つのルート プロジェクトを中心に構成され、その下に複数のサブプロジェクトを含めることができます。

gradle project

ディレクトリ構造は次のようになります:

├── .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 サブモジュールの活用

クリーン アーキテクチャは、関心事の分離を強調する設計パターンであり、ソフトウェアの保守とテストが容易になります。このアーキテクチャをプロジェクトに実装する実際的な方法の 1 つは、Gradle のサブモジュール構造を使用してコードベースを編成することです。 Clean Architecture と Gradle サブモジュールを調整する方法は次のとおりです:

クリーンなアーキテクチャ層:
コア:

  • ビジネス ロジック、ドメイン モデル、アプリケーション ルールが含まれます。 外部または Web に依存しません。
  • 可能な限りフレームワーク固有の実装から独立させる必要があります。

外部:

  • データベースの移行やサードパーティのサービスとのやり取りなど、外部のアクションや統合を処理します。
  • ビジネス ロジックはコアに依存する可能性がありますが、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 プロジェクトを作成し、外部 という名前を付けます。

ステップ 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 を使用して、外部プロジェクトの resource/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 がマルチプロジェクト ビルドをサポートし、複雑なプロジェクトを管理しやすいサブプロジェクトに編成し、それぞれが独自のビルド構成を持ち、ルート ビルド スクリプトの下に統合される方法についても説明しました。

最後に、クリーン アーキテクチャと Gradle モジュールを調整し、プロジェクトをコア層、外部層、Web 層に構造化し、懸念事項と依存関係管理の明確な分離を促進しました。

これらの実践により、モジュール性、自動化、保守性が強化され、スケーラブルでエラーのないソフトウェア開発の準備が整えられます。

以上がマルチモジュール Gradle プロジェクトでの Flyway の移行 (クリーン アーキテクチャ)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート