Maison Java javaDidacticiel Migrations de voies de migration dans les projets Gradle multi-modules (architecture propre)

Migrations de voies de migration dans les projets Gradle multi-modules (architecture propre)

Jan 19, 2025 am 08:05 AM

Automatisation des migrations de bases de données en Java avec Flyway

Les migrations de bases de données sont un aspect crucial du développement logiciel, en particulier dans les environnements où l'intégration et la livraison continues (CI/CD) sont une pratique courante. À mesure que votre application grandit et évolue, le schéma de base de données dont elle dépend doit également évoluer. La gestion manuelle de ces modifications de schéma peut entraîner des erreurs et prendre beaucoup de temps.

Entrez dans Flyway, un outil open source inestimable conçu pour simplifier les migrations de bases de données. Flyway introduit le contrôle de version dans votre base de données, vous permettant de migrer votre schéma en toute sécurité et avec fiabilité. Dans cet article, nous explorerons comment automatiser les migrations de bases de données dans un projet Java Gragle multi-modules à l'aide de Flyway, garantissant que la gestion des modifications de la base de données devienne un processus rationalisé et résistant aux erreurs.

Plus de détails sur la voie de migration

Comprendre les builds multi-projets dans Gradle

Alors que certains projets plus petits ou applications monolithiques peuvent fonctionner avec un seul fichier de construction et une structure source unifiée, les projets plus importants sont souvent organisés en plusieurs modules interdépendants. Le terme « interdépendant » est ici clé, soulignant la nécessité de connecter ces modules via un processus de construction unique.

Gradle répond à cette configuration avec sa capacité de construction multi-projets, souvent qualifiée de projet multi-module. Dans la terminologie de Gradle, ces modules sont appelés sous-projets.

Une construction multi-projets est structurée autour d'un projet racine et peut inclure plusieurs sous-projets en dessous.

gradle project

La structure des répertoires devrait ressembler à ceci :

├── .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)
Copier après la connexion
Copier après la connexion

(1) Le fichier settings.gradle.kts doit inclure tous les sous-projets.
(2) Chaque sous-projet doit avoir son propre fichier build.gradle.kts.

Tirer parti des sous-modules Gradle pour une architecture propre

L'architecture propre est un modèle de conception qui met l'accent sur la séparation des préoccupations, rendant les logiciels plus faciles à maintenir et à tester. L'un des moyens pratiques de mettre en œuvre cette architecture dans un projet consiste à utiliser la structure de sous-modules de Gradle pour organiser votre base de code. Voici comment aligner Clean Architecture avec les sous-modules Gradle :

Couches d'architecture propres :
Noyau :

  • Contient la logique métier, les modèles de domaine et les règles d'application. N'a aucune dépendance vis-à-vis de l'externe ou du Web.
  • Devrait être indépendant des implémentations spécifiques au framework lorsque cela est possible.

Externe :

  • Gère les actions ou intégrations externes, telles que les migrations de bases de données ou les interactions avec des services tiers.
  • Peut dépendre de Core pour la logique métier mais ne devrait pas dépendre du Web.

Web :

  • Le point d'entrée, exposant une API REST et gérant les requêtes HTTP.
  • Dépend de Core pour la logique métier et peut dépendre d'External pour les intégrations.
├── .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)
Copier après la connexion
Copier après la connexion

Étape 1 : Créez un projet Gradle basé sur Java et nommez-le « SchoolStaff ».

Étape 2 : Accédez à Spring Initializr et générez un projet API REST nommé Web.

Étape 3 : Créez un projet Gradle basé sur Java et nommez-le Externe.

Étape 4 : Créez un projet Gradle basé sur Java et nommez-le Core.

Racine 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
Copier après la connexion

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()
    }
}
Copier après la connexion

Dépendances requises pour le projet "Web".

rootProject.name = "SchoolStaff"

include("Core", "External", "Web")
Copier après la connexion

Dépendances requises pour le projet "Core".

dependencies {
    implementation(project(":Core"))
    implementation(project(":External"))
}
Copier après la connexion

Dépendances requises pour le projet "Externe".

dependencies {
    runtimeOnly(project(":External"))
}
Copier après la connexion

Nous utilisons le plugin suivant pour la migration 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"))
}
Copier après la connexion

Cette approche est bien adaptée aux environnements de production, car elle garantit des migrations contrôlées et fiables. Au lieu d'exécuter automatiquement les migrations à chaque démarrage d'application, nous les exécutons uniquement lorsque cela est nécessaire, offrant ainsi une plus grande flexibilité et un meilleur contrôle.

Nous utilisons également le fichier application.properties dans l'application Spring pour gérer les connexions à la base de données et les informations d'identification. Le paramètre baselineOnMigrate = true garantit que la migration initiale est utilisée comme référence pour les migrations futures.

 plugins {
    id("org.flywaydb.flyway") version "11.0.1"
}
Copier après la connexion

Nous pouvons utiliser JPA Buddy pour générer tous les fichiers de migration dans le répertoire resources/db/migration du projet externe.

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
}
Copier après la connexion

Depuis le projet racine, nous pouvons exécuter la migration Flyway à l'aide de la commande suivante :

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)
);
Copier après la connexion

Cela appliquera tous les fichiers de migration à la base de données.

Conclusion

Nous avons exploré comment automatiser les migrations de bases de données à l'aide de Flyway dans un projet multi-module Gradle, ce qui est crucial pour maintenir la cohérence des schémas dans les environnements CI/CD.

Nous avons également expliqué comment Gradle prend en charge les builds multi-projets, en organisant les projets complexes en sous-projets gérables, chacun avec sa propre configuration de build, unifiés sous un script de build racine.

Enfin, nous avons aligné Clean Architecture avec les modules Gradle, structurant le projet en couches Core, Externe et Web, favorisant une séparation nette des préoccupations et de la gestion des dépendances.

Ces pratiques améliorent la modularité, l'automatisation et la maintenabilité, ouvrant la voie à un développement logiciel évolutif et sans erreur.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment fonctionne le mécanisme de chargement de classe de Java, y compris différents chargeurs de classe et leurs modèles de délégation? Comment fonctionne le mécanisme de chargement de classe de Java, y compris différents chargeurs de classe et leurs modèles de délégation? Mar 17, 2025 pm 05:35 PM

Le chargement de classe de Java implique le chargement, la liaison et l'initialisation des classes à l'aide d'un système hiérarchique avec Bootstrap, Extension et Application Classloaders. Le modèle de délégation parent garantit que les classes de base sont chargées en premier, affectant la classe de classe personnalisée LOA

Comment implémenter la mise en cache à plusieurs niveaux dans les applications Java à l'aide de bibliothèques comme la caféine ou le cache de goyave? Comment implémenter la mise en cache à plusieurs niveaux dans les applications Java à l'aide de bibliothèques comme la caféine ou le cache de goyave? Mar 17, 2025 pm 05:44 PM

L'article examine la mise en œuvre de la mise en cache à plusieurs niveaux en Java à l'aide de la caféine et du cache de goyave pour améliorer les performances de l'application. Il couvre les avantages de configuration, d'intégration et de performance, ainsi que la gestion de la politique de configuration et d'expulsion le meilleur PRA

Comment puis-je utiliser JPA (Java Persistance API) pour la cartographie relationnelle des objets avec des fonctionnalités avancées comme la mise en cache et le chargement paresseux? Comment puis-je utiliser JPA (Java Persistance API) pour la cartographie relationnelle des objets avec des fonctionnalités avancées comme la mise en cache et le chargement paresseux? Mar 17, 2025 pm 05:43 PM

L'article discute de l'utilisation de JPA pour la cartographie relationnelle des objets avec des fonctionnalités avancées comme la mise en cache et le chargement paresseux. Il couvre la configuration, la cartographie des entités et les meilleures pratiques pour optimiser les performances tout en mettant en évidence les pièges potentiels. [159 caractères]

Comment utiliser Maven ou Gradle pour la gestion avancée de projet Java, la création d'automatisation et la résolution de dépendance? Comment utiliser Maven ou Gradle pour la gestion avancée de projet Java, la création d'automatisation et la résolution de dépendance? Mar 17, 2025 pm 05:46 PM

L'article discute de l'utilisation de Maven et Gradle pour la gestion de projet Java, la construction de l'automatisation et la résolution de dépendance, en comparant leurs approches et leurs stratégies d'optimisation.

Mar 17, 2025 pm 05:45 PM

L'article discute de la création et de l'utilisation de bibliothèques Java personnalisées (fichiers JAR) avec un versioning approprié et une gestion des dépendances, à l'aide d'outils comme Maven et Gradle.

See all articles