1. Überblick über den Migrationsmechanismus
1.1 Konzept und Rolle der Migration
Datenbankmigration ist der Prozess der Synchronisierung von Änderungen in Datenmodellen mit der Datenbankstruktur, was für die Datenpersistenz entscheidend ist. Mit jeder neuen Version der Anwendung werden häufig Änderungen am Datenmodell vorgenommen, wie das Hinzufügen oder Löschen von Feldern oder das Modifizieren von Indizes. Die Migration ermöglicht es Entwicklern, diese Änderungen auf versionierte und systematische Weise zu verwalten, um die Konsistenz zwischen der Datenbankstruktur und dem Datenmodell sicherzustellen.
In der modernen Webentwicklung bietet der Migrationsmechanismus folgende Vorteile:
- Versionskontrolle: Migrationsdateien können die Änderungshistorie der Datenbankstruktur verfolgen, was es bequem macht, Änderungen in jeder Version zurückzuverfolgen und zu verstehen.
- Automatisierte Bereitstellung: Durch den Migrationsmechanismus können Datenbankbereitstellung und -aktualisierungen automatisiert werden, was die Möglichkeit manueller Eingriffe und das Risiko von Fehlern reduziert.
- Teamarbeit: Migrationsdateien stellen sicher, dass Teammitglieder in verschiedenen Entwicklungsumgebungen synchronisierte Datenbankstrukturen verwenden, was die gemeinsame Entwicklung erleichtert.
1.2 Migrationsfunktionen des ent
-Frameworks
Die Integration des ent
-Frameworks mit dem Migrationsmechanismus bietet folgende Funktionen:
-
Deklarative Programmierung: Entwickler müssen sich nur auf die Go-Repräsentation der Entitäten konzentrieren, und das
ent
-Framework wird die Konvertierung der Entitäten in Datenbanktabellen übernehmen. -
Automatische Migration:
ent
kann automatisch Datenbanktabellenstrukturen erstellen und aktualisieren, ohne dass manuell DDL-Anweisungen geschrieben werden müssen. -
Flexible Kontrolle:
ent
bietet verschiedene Konfigurationsoptionen zur Unterstützung unterschiedlicher Migrationsanforderungen, z.B. mit oder ohne Fremdschlüsselbeschränkungen und zur Generierung global eindeutiger IDs.
2. Einführung in die automatische Migration
2.1 Grundprinzipien der automatischen Migration
Die automatische Migrationsfunktion des ent
-Frameworks basiert auf den Schemadefinitionsdateien (typischerweise im Verzeichnis ent/schema
), um die Datenbankstruktur zu generieren. Nachdem Entwickler Entitäten und Beziehungen definiert haben, überprüft ent
die vorhandene Struktur in der Datenbank und generiert entsprechende Operationen zum Erstellen von Tabellen, Hinzufügen oder Modifizieren von Spalten, Erstellen von Indizes usw.
Darüber hinaus funktioniert das automatische Migrationsprinzip von ent
im "Anhänge-Modus": Es fügt standardmäßig nur neue Tabellen, neue Indizes oder Spalten zu Tabellen hinzu und löscht keine vorhandenen Tabellen oder Spalten. Diese Gestaltung ist vorteilhaft, um versehentlichen Datenverlust zu verhindern und die Datenbankstruktur einfach in vorwärtsgerichteter Weise zu erweitern.
2.2 Verwendung der automatischen Migration
Die Grundschritte zur Verwendung der automatischen Migration von ent
sind wie folgt:
package main
import (
"context"
"log"
"ent"
)
func main() {
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
if err != nil {
log.Fatalf("Verbindung zu MySQL fehlgeschlagen: %v", err)
}
defer client.Close()
ctx := context.Background()
// Führen Sie die automatische Migration aus, um das Datenbankschema zu erstellen oder zu aktualisieren
if err := client.Schema.Create(ctx); err != nil {
log.Fatalf("Fehler beim Erstellen des Datenbankschemas: %v", err)
}
}
Im obigen Code ist ent.Open
für den Aufbau einer Verbindung zur Datenbank und die Rückgabe einer Client-Instanz verantwortlich, während client.Schema.Create
die tatsächliche automatische Migrationsoperation ausführt.
3. Fortgeschrittene Anwendungen der automatischen Migration
3.1 Löschen von Spalten und Indizes
In einigen Fällen müssen möglicherweise Spalten oder Indizes, die nicht mehr benötigt werden, aus dem Datenbankschema entfernt werden. Zu diesem Zeitpunkt können die Optionen WithDropColumn
und WithDropIndex
verwendet werden. Zum Beispiel:
// Migration mit Optionen zum Löschen von Spalten und Indizes ausführen.
err = client.Schema.Create(
ctx,
migrate.WithDropIndex(true),
migrate.WithDropColumn(true),
)
Dieser Codeausschnitt ermöglicht die Konfiguration zum Löschen von Spalten und Indizes während der automatischen Migration. ent
löscht alle Spalten und Indizes, die nicht in der Schemadefinition existieren, wenn die Migration ausgeführt wird.
3.2 Globale eindeutige ID
Standardmäßig beginnen die Primärschlüssel in SQL-Datenbanken für jede Tabelle bei 1, und verschiedene Entitätstypen können dieselbe ID teilen. In einigen Anwendungsszenarien, z.B. bei der Verwendung von GraphQL, ist es möglicherweise erforderlich, globale Eindeutigkeit für die IDs von Objekten verschiedener Entitätstypen bereitzustellen. In ent
kann dies mit der Option WithGlobalUniqueID
konfiguriert werden:
// Migration mit global eindeutigen IDs für jede Entität ausführen.
if err := client.Schema.Create(ctx, migrate.WithGlobalUniqueID(true)); err != nil {
log.Fatalf("Fehler beim Erstellen des Datenbankschemas: %v", err)
}
Nach Aktivierung der Option WithGlobalUniqueID
weist ent
jeder Entität in einer Tabelle namens ent_types
einen ID-Bereich von 2^32 zu, um globale Eindeutigkeit zu erreichen.
3.3 Offline-Modus
Der Offline-Modus ermöglicht es, Schemaänderungen nicht direkt in der Datenbank auszuführen, sondern sie stattdessen in einen io.Writer
zu schreiben. Das ist nützlich, um SQL-Befehle zu überprüfen, bevor die Änderungen wirksam werden, oder um ein SQL-Skript für die manuelle Ausführung zu generieren. Zum Beispiel:
// Migrationsschritte in eine Datei schreiben
f, err := os.Create("migrate.sql")
if err != nil {
log.Fatalf("Fehler beim Erstellen der Migrationsdatei: %v", err)
}
defer f.Close()
if err := client.Schema.WriteTo(ctx, f); err != nil {
log.Fatalf("Fehler beim Schreiben der Migrations-Schemaänderungen: %v", err)
}
Dieser Code schreibt die Migrationsänderungen in eine Datei namens migrate.sql
. In der Praxis können Entwickler wählen, ob sie direkt auf die Standardausgabe drucken oder die Änderungen zur Überprüfung oder Archivierung in eine Datei schreiben.
4. Unterstützung für Fremdschlüssel und benutzerdefinierte Hooks
4.1 Aktivieren oder Deaktivieren von Fremdschlüsseln
In Ent werden Fremdschlüssel durch die Definition von Beziehungen (Edges) zwischen Entitäten implementiert, und diese Fremdschlüsselbeziehungen werden automatisch auf Datenbankebene erstellt, um die Datenintegrität und -konsistenz durchzusetzen. In bestimmten Situationen, wie z.B. zur Leistungsoptimierung oder wenn die Datenbank keine Fremdschlüssel unterstützt, können Sie diese deaktivieren.
Um Fremdschlüsselbedingungen in Migrationen zu aktivieren oder zu deaktivieren, können Sie dies über die Konfigurationsoption WithForeignKeys
steuern:
// Fremdschlüssel aktivieren
err = client.Schema.Create(
ctx,
migrate.WithForeignKeys(true),
)
if err != nil {
log.Fatalf("Fehler beim Erstellen von Schemaresourcen mit Fremdschlüsseln: %v", err)
}
// Fremdschlüssel deaktivieren
err = client.Schema.Create(
ctx,
migrate.WithForeignKeys(false),
)
if err != nil {
log.Fatalf("Fehler beim Erstellen von Schemaresourcen ohne Fremdschlüssel: %v", err)
}
Diese Konfigurationsoption muss beim Aufruf von Schema.Create
übergeben werden und bestimmt, ob Fremdschlüsselbedingungen im generierten DDL basierend auf dem angegebenen Wert enthalten sein sollen.
4.2 Anwendung von Migrations-Hooks
Migrations-Hooks sind benutzerdefinierte Logiken, die an verschiedenen Stellen der Migrationsausführung eingefügt und ausgeführt werden können. Sie sind sehr nützlich, um spezifische Logik in der Datenbank vor/nach der Migration auszuführen, wie z.B. die Validierung von Migrationsergebnissen und das Vorabfüllen von Daten.
Hier ist ein Beispiel, wie benutzerdefinierte Migrations-Hooks implementiert werden können:
func customHook(next schema.Creator) schema.Creator {
return schema.CreateFunc(func(ctx context.Context, tables ...*schema.Table) error {
// Benutzerdefinierter Code, der vor der Migration ausgeführt werden soll
// Zum Beispiel Logging, Überprüfung bestimmter Voraussetzungen usw.
log.Println("Benutzerdefinierte Logik vor der Migration")
// Den nächsten Hook oder die standardmäßige Migrationslogik aufrufen
err := next.Create(ctx, tables...)
if err != nil {
return err
}
// Benutzerdefinierter Code, der nach der Migration ausgeführt werden soll
// Zum Beispiel Bereinigung, Datenmigration, Sicherheitsüberprüfungen usw.
log.Println("Benutzerdefinierte Logik nach der Migration")
return nil
})
}
// Verwendung von benutzerdefinierten Hooks in der Migration
err := client.Schema.Create(
ctx,
schema.WithHooks(customHook),
)
if err != nil {
log.Fatalf("Fehler beim Anwenden von benutzerdefinierten Migrations-Hooks: %v", err)
}
Hooks sind leistungsstarke und unverzichtbare Werkzeuge für komplexe Migrationen, die Ihnen die direkte Kontrolle über das Migrationsverhalten der Datenbank geben, wenn dies erforderlich ist.
5. Versionierte Migrationen
5.1 Einführung in versionierte Migrationen
Versionierte Migration ist ein Muster zur Verwaltung von Datenbankmigrationen, das es Entwicklern ermöglicht, Änderungen an der Datenbankstruktur in mehrere Versionen aufzuteilen, von denen jede eine bestimmte Reihe von Befehlen zur Datenbankmodifikation enthält. Im Vergleich zur automatischen Migration bietet die versionierte Migration eine feinere Kontrolle, die die Rückverfolgbarkeit und Umkehrbarkeit von Datenbankstrukturänderungen sicherstellt.
Der Hauptvorteil der versionierten Migration ist die Unterstützung von Vorwärts- und Rückwärtsmigrationen (d.h. Upgrade oder Downgrade), die es Entwicklern ermöglicht, spezifische Änderungen anzuwenden, rückgängig zu machen oder zu überspringen, wenn dies erforderlich ist. Bei der Zusammenarbeit in einem Team stellt versionierte Migration sicher, dass jedes Mitglied an derselben Datenbankstruktur arbeitet und reduziert Probleme durch Inkonsistenzen.
Automatische Migration ist oft nicht umkehrbar und erzeugt und führt SQL-Anweisungen aus, um den neuesten Stand der Entitätsmodelle abzugleichen, hauptsächlich in Entwicklungsphasen oder kleinen Projekten.
5.2 Verwendung von versionierten Migrationen
1. Atlas-Tool installieren
Bevor Sie versionierte Migrationen verwenden, müssen Sie das Atlas
-Tool auf Ihrem System installieren. Atlas
ist ein Migrationstool, das mehrere Datenbanksysteme unterstützt und leistungsstarke Funktionen zur Verwaltung von Datenbankschemawechseln bietet.
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. Generieren von Migrationsdateien basierend auf aktuellen Entitätsdefinitionen
atlas migrate diff migration_name \
--dir "file://ent/migrate/migrations" \
--to "ent://ent/schema" \
--dev-url "docker://mysql/8/ent"
3. Anwendungs-Migrationsdateien
Sobald die Migrationsdateien generiert sind, können sie auf die Entwicklungs-, Test- oder Produktionsumgebungen angewendet werden. Normalerweise würden Sie diese Migrationsdateien zunächst auf eine Entwicklungs- oder Testdatenbank anwenden, um sicherzustellen, dass sie wie erwartet ausgeführt werden. Anschließend würden dieselben Migrationschritte in der Produktionsumgebung ausgeführt.
atlas migrate apply \
--dir "file://ent/migrate/migrations" \
--url "mysql://root:pass@localhost:3306/example"
Verwenden Sie den Befehl atlas migrate apply
, indem Sie das Verzeichnis der Migrationsdateien (--dir
) und die URL der Ziel-Datenbank (--url
) angeben, um die Migrationsdateien anzuwenden.