


Migrations de voies de migration dans les projets Gradle multi-modules (architecture propre)
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.
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)
(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)
É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
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() } }
Dépendances requises pour le projet "Web".
rootProject.name = "SchoolStaff" include("Core", "External", "Web")
Dépendances requises pour le projet "Core".
dependencies { implementation(project(":Core")) implementation(project(":External")) }
Dépendances requises pour le projet "Externe".
dependencies { runtimeOnly(project(":External")) }
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")) }
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" }
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 }
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) );
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!

Outils d'IA chauds

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

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

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

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

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

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

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]

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.
