Comment utiliser les migrations avec Golang
Exemple d'application simple montrant comment utiliser golang-migrate
Pourquoi devriez-vous utiliser les migrations ?
Beaucoup de gens posent cette question et j'ai essayé de faire cette liste pour mettre en évidence les principaux avantages de l'utilisation des migrations :
Contrôle de version : L'un des principaux et des plus importants est de pouvoir avoir un versionnage des différentes modifications du schéma de la base de données. Sans les migrations, ces modifications de schéma seraient incohérentes et impossibles à suivre, ce qui entraînerait des problèmes de version et d'éventuelles erreurs.
Rollback : Il est toujours nécessaire d'avoir un système de rollback en cas de panne. Un système de migrations dispose toujours de deux méthodes :-)
Automation et intégration CI/CD : Les migrations peuvent être automatisées, leur permettant de faire partie du pipeline CI/CD. Cela aide à déployer les changements de manière fluide et cohérente sans intervention manuelle.
Nous pouvons trouver bien d'autres avantages mais je pense que ces points représentent un bon résumé des principaux avantages.
Comment mettre en œuvre les migrations dans Golang ?
Go ne prend pas en charge les migrations de manière native pour cette raison, nous pouvons également utiliser le package populaire golang-migrate si vous utilisez un ORM comme GORM, vous pouvez l'utiliser pour cela.
Les deux packages sont très populaires mais dans cet exemple, j'utiliserai golang-migrate car je ne suis pas intéressé par l'implémentation d'un ORM.
Montre-moi le code !
Voyons étape par étape comment implémenter une application simple pour voir comment elle est utilisée.
Pour suivre cet article vous aurez besoin de : Go et Docker avec Docker Compose
Infrastructure
Créez le fichier docker-compose.yml dans votre répertoire racine où nous définirons votre base de données préférée, dans mon cas utilisez une MariaDB mais n'hésitez pas à en utiliser une autre.
services: mariadb: image: mariadb:11.5.2 container_name: mariadb_example_go_migration ports: - "3306:3306" environment: - MYSQL_DATABASE=app - MYSQL_ROOT_PASSWORD=root - TZ=Europe/Berlin volumes: - mariadbdata:/var/lib/mysql volumes: mariadbdata: driver: local docker compose up -d
Si vous préférez, vous pouvez utiliser Docker directement au lieu de docker-compose :
docker volume create -d local mariadbdata docker run --name mariadb_example_go_migration -p 3306:3306 -e MYSQL_DATABASE=app -e MYSQL_ROOT_PASSWORD=root -e TZ=Europe/Berlin -v mariadbdata:/var/lib/mysql mariadb:11.5.2
Valeurs environnementales
Créez ou mettez à jour le fichier .env dans votre répertoire racine où vous devez définir les variables pour connecter notre base de données.
DATABASE_DSN=root:root@tcp(localhost:3306)/app
Créez une application Golang simple
Créez une application Golang simple pour garantir une connexion réussie à la base de données et répertoriez toutes les tables et structures de la base de données avec leur structure. cmd/main.go
package main import ( "database/sql" "fmt" "log" "os" "text/tabwriter" _ "github.com/go-sql-driver/mysql" "github.com/joho/godotenv" ) func main() { // Load .env variables err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Open connection with MySQL DB db, err := sql.Open("mysql", os.Getenv("DATABASE_DSN")) if err != nil { log.Fatalf("Error opening database: %v\n", err) } defer db.Close() // Ensure that the connection works err = db.Ping() if err != nil { log.Fatalf("Error connecting database: %v\n", err) } fmt.Println("Connected to database") // Execute the SHOW TABLES query to list all tables in the database tables, err := db.Query("SHOW TABLES") if err != nil { log.Fatalf("Failed to execute SHOW TABLES query: %v\n", err) } defer tables.Close() fmt.Println("Database structure:") for tables.Next() { var tableName string if err := tables.Scan(&tableName); err != nil { log.Fatalf("Failed to scan table name: %v\n", err) } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', tabwriter.Debug) fmt.Printf("\n[Table: %s]\n\n", tableName) fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", "Field", "Type", "Null", "Key", "Default", "Extra") // Get the structure of the current table structureQuery := fmt.Sprintf("DESCRIBE %s", tableName) columns, err := db.Query(structureQuery) if err != nil { log.Fatalf("Failed to describe table %s: %v\n", tableName, err) } defer columns.Close() for columns.Next() { var field, colType, null, key, defaultVal, extra sql.NullString err := columns.Scan(&field, &colType, &null, &key, &defaultVal, &extra) if err != nil { log.Fatalf("Failed to scan column: %v\n", err) } fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", field.String, colType.String, null.String, key.String, defaultVal.String, extra.String) } w.Flush() } }
Et lorsque nous l'exécutons, nous obtenons un résultat similaire :
Migrer la CLI
Pour exécuter golang-migrate CLI, vous disposez essentiellement de deux méthodes : installer la CLI localement ou exécuter via l'image Docker officielle : migrate/migrate.
Personnellement, je préfère la variante Docker mais dans ce tutoriel, illustrez les deux variantes.
Comment générer une migration
La première étape consiste à créer une migration vide avec la commande suivante.
services: mariadb: image: mariadb:11.5.2 container_name: mariadb_example_go_migration ports: - "3306:3306" environment: - MYSQL_DATABASE=app - MYSQL_ROOT_PASSWORD=root - TZ=Europe/Berlin volumes: - mariadbdata:/var/lib/mysql volumes: mariadbdata: driver: local docker compose up -d
docker volume create -d local mariadbdata docker run --name mariadb_example_go_migration -p 3306:3306 -e MYSQL_DATABASE=app -e MYSQL_ROOT_PASSWORD=root -e TZ=Europe/Berlin -v mariadbdata:/var/lib/mysql mariadb:11.5.2
- ext : Extension du fichier à générer.
- dir : Répertoire où notre migration sera créée.
- seq : Nom de la séquence de migration.
Cette commande générera deux fichiers vides sur le dossier database/migrations/ : 000001createuserstable.up.sql et 000001createuserstable.down.sql
Dans le fichier 000001createuserstable.up.sql, définissez SQL pour créer une table d'utilisateurs :
DATABASE_DSN=root:root@tcp(localhost:3306)/app
Dans le fichier 000001createuserstable.down.sql, définissez SQL pour annuler toutes les modifications apportées par up, dans ce cas nous devons supprimer la table des utilisateurs :
package main import ( "database/sql" "fmt" "log" "os" "text/tabwriter" _ "github.com/go-sql-driver/mysql" "github.com/joho/godotenv" ) func main() { // Load .env variables err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Open connection with MySQL DB db, err := sql.Open("mysql", os.Getenv("DATABASE_DSN")) if err != nil { log.Fatalf("Error opening database: %v\n", err) } defer db.Close() // Ensure that the connection works err = db.Ping() if err != nil { log.Fatalf("Error connecting database: %v\n", err) } fmt.Println("Connected to database") // Execute the SHOW TABLES query to list all tables in the database tables, err := db.Query("SHOW TABLES") if err != nil { log.Fatalf("Failed to execute SHOW TABLES query: %v\n", err) } defer tables.Close() fmt.Println("Database structure:") for tables.Next() { var tableName string if err := tables.Scan(&tableName); err != nil { log.Fatalf("Failed to scan table name: %v\n", err) } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', tabwriter.Debug) fmt.Printf("\n[Table: %s]\n\n", tableName) fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", "Field", "Type", "Null", "Key", "Default", "Extra") // Get the structure of the current table structureQuery := fmt.Sprintf("DESCRIBE %s", tableName) columns, err := db.Query(structureQuery) if err != nil { log.Fatalf("Failed to describe table %s: %v\n", tableName, err) } defer columns.Close() for columns.Next() { var field, colType, null, key, defaultVal, extra sql.NullString err := columns.Scan(&field, &colType, &null, &key, &defaultVal, &extra) if err != nil { log.Fatalf("Failed to scan column: %v\n", err) } fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", field.String, colType.String, null.String, key.String, defaultVal.String, extra.String) } w.Flush() } }
Comment appliquer la migration
La commande suivante applique toutes les migrations en attente. Vous pouvez également définir le nombre de migrations à appliquer en additionnant le nombre après le haut.
#CLI variant migrate create -ext sql -dir ./database/migrations -seq create_users_table
#Docker CLI variant docker run --rm -v $(pwd)/database/migrations:/migrations migrate/migrate \ create -ext sql -dir /migrations -seq create_users_table
- path : chemin d’accès au répertoire des migrations.
- base de données : définissez votre connexion DSN à la base de données.
REMARQUE : Lors de la première exécution de la migration une table "schema_migrations" sera créée dans laquelle la migration connaît le numéro de version appliqué.
Et lancez notre application Golang pour afficher les résultats :
Ajout d'une nouvelle migration
Ajouter une nouvelle colonne de téléphone sur la table des utilisateurs
CREATE TABLE `users` ( `id` VARCHAR(36) NOT NULL PRIMARY KEY, `name` VARCHAR(255) NOT NULL, `email` VARCHAR(255) NOT NULL UNIQUE, `password` VARCHAR(255) NOT NULL );
DROP TABLE IF EXISTS `users`;
#CLI variant migrate -path=./database/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
#Docker CLI variant docker run --rm -v $(pwd)/database/migrations:/migrations --network host migrate/migrate \ -path=/migrations -database "mysql://root:root@tcp(localhost:3306)/app" up
Et lorsque vous l'exécutez depuis notre application Golang, vous pouvez voir le nouveau champ :
Comment annuler la migration
Avec la commande suivante, nous pouvons facilement annuler le fichier appliqué. migrations. Dans l'exemple suivant, nous pouvons voir comment nous annulons la dernière migration appliquée :
#CLI variant migrate create -ext sql -dir ./database/migrations -seq add_column_phone #Docker CLI variant docker run --rm -v $(pwd)/database/migrations:/migrations migrate/migrate \ create -ext sql -dir /migrations -seq add_column_phone
-- 000002_add_column_phone.up.sql ALTER TABLE `users` ADD `phone` VARCHAR(255) NULL;
ATTENTION : Si vous ne définissez pas le nombre de migrations, le ROLLBACK sera appliqué à TOUTES LES MIGRATIONS !
Et puis nous pouvons montrer que la dernière migration a été annulée et que le champ téléphone a été supprimé :-)
Comment résoudre les erreurs de migration
Si une migration contient des erreurs et est exécutée, cette migration ne peut pas être appliquée et le système de migration empêchera toute autre migration sur la base de données jusqu'à ce que cette migration soit corrigée.
Et lorsque nous essaierons de postuler, nous recevrons un message comme celui-ci :
services: mariadb: image: mariadb:11.5.2 container_name: mariadb_example_go_migration ports: - "3306:3306" environment: - MYSQL_DATABASE=app - MYSQL_ROOT_PASSWORD=root - TZ=Europe/Berlin volumes: - mariadbdata:/var/lib/mysql volumes: mariadbdata: driver: local docker compose up -d
Pas de panique, il n'est pas difficile de revenir à un système cohérent.
Nous devons d'abord résoudre la migration corrompue, dans ce cas la version 2.
Une fois la migration résolue, nous devons forcer le système à la dernière version valide, en l'occurrence la version 1.
docker volume create -d local mariadbdata docker run --name mariadb_example_go_migration -p 3306:3306 -e MYSQL_DATABASE=app -e MYSQL_ROOT_PASSWORD=root -e TZ=Europe/Berlin -v mariadbdata:/var/lib/mysql mariadb:11.5.2
DATABASE_DSN=root:root@tcp(localhost:3306)/app
Et maintenant vous pouvez réappliquer les migrations sans aucun problème ;-)
Makefile
Pour améliorer notre productivité et faciliter l'utilisation de ces commandes nous pouvons utiliser Makefile. Ci-dessous vous pouvez voir les deux variantes : client natif et docker.
Variante CLI
package main import ( "database/sql" "fmt" "log" "os" "text/tabwriter" _ "github.com/go-sql-driver/mysql" "github.com/joho/godotenv" ) func main() { // Load .env variables err := godotenv.Load() if err != nil { log.Fatal("Error loading .env file") } // Open connection with MySQL DB db, err := sql.Open("mysql", os.Getenv("DATABASE_DSN")) if err != nil { log.Fatalf("Error opening database: %v\n", err) } defer db.Close() // Ensure that the connection works err = db.Ping() if err != nil { log.Fatalf("Error connecting database: %v\n", err) } fmt.Println("Connected to database") // Execute the SHOW TABLES query to list all tables in the database tables, err := db.Query("SHOW TABLES") if err != nil { log.Fatalf("Failed to execute SHOW TABLES query: %v\n", err) } defer tables.Close() fmt.Println("Database structure:") for tables.Next() { var tableName string if err := tables.Scan(&tableName); err != nil { log.Fatalf("Failed to scan table name: %v\n", err) } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', tabwriter.Debug) fmt.Printf("\n[Table: %s]\n\n", tableName) fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", "Field", "Type", "Null", "Key", "Default", "Extra") // Get the structure of the current table structureQuery := fmt.Sprintf("DESCRIBE %s", tableName) columns, err := db.Query(structureQuery) if err != nil { log.Fatalf("Failed to describe table %s: %v\n", tableName, err) } defer columns.Close() for columns.Next() { var field, colType, null, key, defaultVal, extra sql.NullString err := columns.Scan(&field, &colType, &null, &key, &defaultVal, &extra) if err != nil { log.Fatalf("Failed to scan column: %v\n", err) } fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t\n", field.String, colType.String, null.String, key.String, defaultVal.String, extra.String) } w.Flush() } }
Variante Docker CLI
#CLI variant migrate create -ext sql -dir ./database/migrations -seq create_users_table
Dépôt
Le code de ce tutoriel peut être trouvé dans le public : GitHub - albertcolom/example-go-migration
Original publié sur : albertcolom.com
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)

Sujets chauds

GO Language Pack Import: Quelle est la différence entre le soulignement et sans soulignement?

Comment mettre en œuvre le transfert d'informations à court terme entre les pages du cadre Beego?

Comment convertir la liste des résultats de la requête MySQL en une tranche de structure personnalisée dans le langage Go?

Comment puis-je définir des contraintes de type personnalisé pour les génériques en Go?

Comment écrire des objets et des talons simulés pour les tests en Go?

Comment écrire des fichiers dans GO Language de manière pratique?

Comment rédigez-vous des tests unitaires en Go?

Comment puis-je utiliser des outils de traçage pour comprendre le flux d'exécution de mes applications GO?
