1. Aperçu du mécanisme de migration
1.1 Concept et rôle de la migration
La migration de base de données est le processus de synchronisation des modifications apportées aux modèles de données avec la structure de la base de données, ce qui est crucial pour la persistance des données. À mesure que la version de l'application évolue, le modèle de données subit souvent des changements, tels que l'ajout ou la suppression de champs, ou la modification des index. La migration permet aux développeurs de gérer ces changements de manière versionnée et systématique, garantissant la cohérence entre la structure de la base de données et le modèle de données.
Dans le développement web moderne, le mécanisme de migration offre les avantages suivants :
- Contrôle de version : Les fichiers de migration peuvent suivre l'historique des modifications de la structure de la base de données, ce qui facilite la restauration et la compréhension des modifications dans chaque version.
- Déploiement automatisé : Grâce au mécanisme de migration, le déploiement et les mises à jour de la base de données peuvent être automatisés, réduisant la possibilité d'intervention manuelle et le risque d'erreurs.
- Collaboration d'équipe : Les fichiers de migration garantissent que les membres de l'équipe utilisent des structures de base de données synchronisées dans différents environnements de développement, facilitant le développement collaboratif.
1.2 Caractéristiques de migration du framework ent
L'intégration du framework ent
avec le mécanisme de migration offre les fonctionnalités suivantes :
-
Programmation déclarative : Les développeurs n'ont qu'à se concentrer sur la représentation en Go des entités, et le framework
ent
se chargera de la conversion des entités en tables de base de données. -
Migration automatique :
ent
peut créer et mettre à jour automatiquement les structures de table de base de données sans avoir besoin d'écrire manuellement des instructions DDL. -
Contrôle flexible :
ent
fournit diverses options de configuration pour prendre en charge différentes exigences de migration, notamment avec ou sans contraintes de clé étrangère et la génération d'identifiants globalement uniques.
2. Introduction à la migration automatique
2.1 Principes de base de la migration automatique
La fonctionnalité de migration automatique du framework ent
est basée sur les fichiers de définition de schéma (généralement présents dans le répertoire ent/schema
) pour générer la structure de la base de données. Après que les développeurs aient défini les entités et les relations, ent
inspectera la structure existante dans la base de données et générera les opérations correspondantes pour créer des tables, ajouter ou modifier des colonnes, créer des index, etc.
De plus, le principe de migration automatique de ent
fonctionne en mode "ajout" : par défaut, il ajoute uniquement de nouvelles tables, de nouveaux index ou ajoute des colonnes aux tables, et ne supprime pas les tables ou les colonnes existantes. Cette conception est bénéfique pour éviter la perte accidentelle de données et facilite l'expansion de la structure de la base de données de manière progressive.
2.2 Utilisation de la migration automatique
Les étapes de base pour utiliser la migration automatique de ent
sont les suivantes :
package main
import (
"context"
"log"
"ent"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("Échec de la connexion à MySQL : %v", err)
}
defer client.Close()
ctx := context.Background()
// Effectuer une migration automatique pour créer ou mettre à jour le schéma de la base de données
if err := client.Schema.Create(ctx); err != nil {
log.Fatalf("Échec de la création du schéma de la base de données : %v", err)
}
}
Dans le code ci-dessus, ent.Open
est responsable d'établir une connexion avec la base de données et de renvoyer une instance cliente, tandis que client.Schema.Create
exécute l'opération de migration automatique réelle.
3. Applications avancées de la migration automatique
3.1 Supprimer des colonnes et des index
Dans certains cas, nous devons peut-être supprimer des colonnes ou des index qui ne sont plus nécessaires dans le schéma de la base de données. À ce moment-là, nous pouvons utiliser les options WithDropColumn
et WithDropIndex
. Par exemple :
// Exécuter une migration avec des options pour supprimer des colonnes et des index.
err = client.Schema.Create(
ctx,
migrate.WithDropIndex(true),
migrate.WithDropColumn(true),
)
Cet extrait de code permet de configurer la suppression de colonnes et d'index lors de la migration automatique. ent
supprimera toutes les colonnes et les index qui n'existent pas dans la définition de schéma lors de l'exécution de la migration.
3.2 Identifiant global unique
Par défaut, les clés primaires dans les bases de données SQL commencent à partir de 1 pour chaque table, et différents types d'entités peuvent partager le même identifiant. Dans certains scénarios d'application, comme l'utilisation de GraphQL, il peut être nécessaire de fournir une unicité globale pour les identifiants d'objets de différents types d'entités. Dans ent
, cela peut être configuré en utilisant l'option WithGlobalUniqueID
:
// Exécuter une migration avec des identifiants uniques universels pour chaque entité.
if err := client.Schema.Create(ctx, migrate.WithGlobalUniqueID(true)); err != nil {
log.Fatalf("Échec de la création du schéma de la base de données : %v", err)
}
Après avoir activé l'option WithGlobalUniqueID
, ent
attribuera un identifiant de plage 2^32 à chaque entité dans une table nommée ent_types
pour atteindre une unicité globale.
3.3 Mode Hors Ligne
Le mode hors ligne permet d'écrire les changements de schéma dans un io.Writer
au lieu de les exécuter directement sur la base de données. Il est utile pour vérifier les commandes SQL avant que les modifications ne prennent effet, ou pour générer un script SQL pour une exécution manuelle. Par exemple:
// Sauvegarder les changements de migration dans un fichier
f, err := os.Create("migrate.sql")
if err != nil {
log.Fatalf("Impossible de créer le fichier de migration : %v", err)
}
defer f.Close()
if err := client.Schema.WriteTo(ctx, f); err != nil {
log.Fatalf("Échec de l'impression des changements de schéma de base de données : %v", err)
}
Ce code écrira les changements de migration dans un fichier nommé migrate.sql
. En pratique, les développeurs peuvent choisir d'imprimer directement à la sortie standard ou d'écrire dans un fichier pour examen ou archivage.
4. Support des Clés Étrangères et Hooks Personnalisés
4.1 Activer ou Désactiver les Clés Étrangères
En Ent, les clés étrangères sont implémentées en définissant des relations (edges) entre les entités, et ces relations de clés étrangères sont automatiquement créées au niveau de la base de données pour garantir l'intégrité et la cohérence des données. Cependant, dans certaines situations, comme pour l'optimisation des performances ou lorsque la base de données ne prend pas en charge les clés étrangères, vous pouvez choisir de les désactiver.
Pour activer ou désactiver les contraintes de clés étrangères dans les migrations, vous pouvez contrôler cela via l'option de configuration WithForeignKeys
:
// Activer les clés étrangères
err = client.Schema.Create(
ctx,
migrate.WithForeignKeys(true),
)
if err != nil {
log.Fatalf("Échec de la création des ressources de schéma avec des clés étrangères : %v", err)
}
// Désactiver les clés étrangères
err = client.Schema.Create(
ctx,
migrate.WithForeignKeys(false),
)
if err != nil {
log.Fatalf("Échec de la création des ressources de schéma sans clés étrangères : %v", err)
}
Cette option de configuration doit être passée lors de l'appel de Schema.Create
, et elle détermine si les contraintes de clés étrangères doivent être incluses dans le DDL généré en fonction de la valeur spécifiée.
4.2 Application des Hooks de Migration
Les hooks de migration sont une logique personnalisée pouvant être insérée et exécutée à différentes étapes de l'exécution de la migration. Ils sont très utiles pour effectuer une logique spécifique sur la base de données avant/après la migration, comme la validation des résultats de migration et le pré-remplissage de données.
Voici un exemple de mise en œuvre de hooks de migration personnalisés :
func customHook(next schema.Creator) schema.Creator {
return schema.CreateFunc(func(ctx context.Context, tables ...*schema.Table) error {
// Code personnalisé à exécuter avant la migration
// Par exemple, journalisation, vérification de certaines préconditions, etc.
log.Println("Logique personnalisée avant la migration")
// Appeler le prochain hook ou la logique de migration par défaut
err := next.Create(ctx, tables...)
if err != nil {
return err
}
// Code personnalisé à exécuter après la migration
// Par exemple, nettoyage, migration de données, vérifications de sécurité, etc.
log.Println("Logique personnalisée après la migration")
return nil
})
}
// Utilisation de hooks personnalisés dans la migration
err := client.Schema.Create(
ctx,
schema.WithHooks(customHook),
)
if err != nil {
log.Fatalf("Erreur lors de l'application des hooks de migration personnalisés : %v", err)
}
Les hooks sont des outils puissants et indispensables pour les migrations complexes, vous donnant la possibilité de contrôler directement le comportement de la migration de la base de données lorsque nécessaire.
5. Migrations Versionnées
5.1 Introduction aux Migrations Versionnées
La migration versionnée est un modèle de gestion de la migration de base de données, permettant aux développeurs de diviser les modifications de la structure de la base de données en plusieurs versions, chacune contenant un ensemble spécifique de commandes de modification de la base de données. Comparée à la migration automatique, la migration versionnée offre un contrôle plus fin, garantissant la traçabilité et la réversibilité des modifications de la structure de la base de données.
Le principal avantage de la migration versionnée est son support pour la migration avant et arrière (c'est-à-dire, mise à niveau ou rétrogradation), permettant aux développeurs d'appliquer, d'annuler ou de sauter des modifications spécifiques au besoin. Lors d'une collaboration au sein d'une équipe, la migration versionnée garantit que chaque membre travaille sur la même structure de base de données, réduisant les problèmes causés par les incohérences.
La migration automatique est souvent irréversible, générant et exécutant des instructions SQL pour correspondre à l'état le plus récent des modèles d'entité, principalement utilisée dans les phases de développement ou les petits projets.
5.2 Utilisation des Migrations Versionnées
1. Installation de l'outil Atlas
Avant d'utiliser les migrations versionnées, vous devez installer l'outil Atlas
sur votre système. Atlas
est un outil de migration qui prend en charge plusieurs systèmes de base de données, offrant des fonctionnalités puissantes pour gérer les changements de schéma de base de données.
macOS + Linux
curl -sSf https://atlasgo.sh | sh
Homebrew
brew install ariga/tap/atlas
Docker
docker pull arigaio/atlas
docker run --rm arigaio/atlas --help
Windows
https://release.ariga.io/atlas/atlas-windows-amd64-latest.exe
2. Génération de fichiers de migration basés sur les définitions d'entités actuelles
atlas migrate diff nom_de_migration \
--dir "file://ent/migrate/migrations" \
--to "ent://ent/schema" \
--dev-url "docker://mysql/8/ent"
3. Fichiers de migration d'application
Une fois les fichiers de migration générés, ils peuvent être appliqués aux environnements de développement, de test ou de production. En général, vous appliqueriez d'abord ces fichiers de migration à une base de données de développement ou de test pour vous assurer qu'ils s'exécutent comme prévu. Ensuite, les mêmes étapes de migration seraient exécutées dans l'environnement de production.
atlas migrate apply \
--dir "file://ent/migrate/migrations" \
--url "mysql://root:pass@localhost:3306/example"
Utilisez la commande atlas migrate apply
, en spécifiant le répertoire des fichiers de migration (--dir
) et l'URL de la base de données cible (--url
) pour appliquer les fichiers de migration.