Datenbankmigration ================== > Note|Hinweis: Das Feature zur Datenbankmigration ist seit Verison 1.1.6 verfügbar. Genause wie der Quelltext einer Anwendung verändert sich auch die Struktur der zugehörigen Datenbank während der Entwicklung. So muss z.B. irgendwann eine Tabelle hinzugefügt werden. Oder nachdem die Anwendung produktiv geschaltet wurde, stellt man fest, dass eine Spalte noch dringend einen Index benötigt. Es ist daher genauso wichtig wie beim Quelltext, dass auch die strukturellen Änderungen in der Datenbank festgehalten werden (man spricht hier auch von **Migration**). Wenn Programmcode und Datenbank nicht mehr zueinander passen, ist ein Fehlverhalten praktisch vorprogrammiert. Yii enthält daher ein Tool zur Datenbankmigration, dass eine Historie von Migrationen verwalten, neue Migrationen durchführen oder existierende rückgangig machen kann. Der folgende Ablauf soll verdeutlichen, wie Datenbanmigration bei der Entwicklung eingesetzt wird: 1. Tim erstellt eine Migration (er erstellt z.B. eine neue Tabelle) 2. Tim überträgt seine Änderung in ein Versionskontrollsystem (z.B. SVN, GIT) 3. Doug updated seine Arbeitskopie und erhält die neue Migration 4. Doug wendet die Migration auf seiner lokalen Datenbank an Migrationen werden in Yii über den Kommandozeilenbefehl `yiic migrate` verwaltet. Mit diesem Befehl können neue Migrationen erstellt, angewendet, zurückgenommen oder wiederholt werden. Man kann auch die Historie aller Migrationen oder neue Migrationen anzeigen lassen. Migrationen erstellen --------------------- Um eine neu Migration (z.B. zum Anlegen einer News-Tabelle) zu erzeugen, verwendet man folgenden Befehl: ~~~ yiic migrate create ~~~ Der Parameter `name` dient dazu, die Migration kurz und knapp zu beschreiben (z.B. `erstelle_news_tabellle`). Wie wir weiter unten zeigen, wird dieser Name Bestandteil eines PHP-Klassennamens werden. Er sollte daher nur Buchstaben, Zahlen und/oder Unterstriche enthalten. ~~~ yiic migrate create erstelle_news_tabelle ~~~ Damit wird im Verzeichnis `protected/migrations` eine Datei `m101129-185401_erstelle_news_tabelle.php` mit diesem Inhalt erzeugt: ~~~ [php] class m101129_185401_erstelle_news_tabelle extends CDbMigration { public function up() { } /* public function down() { } */ } ~~~ Beachten Sie, dass der Klassenname dem Dateinamen entspricht und dem Muster `m_` folgt, wobei `` für den UTC-Zeitstempel (im Format `JJMMTT_HHMMSS`) des Erstellzeitpunkts und `` für den obigen Migrationsnamen steht. Die `up()`-Methode sollte den Code für die eigentliche Migration enthalten, `down()` den Code, um die Änderung rückgängig zu machen. Manchmal kommt es vor, dass eine `down()`-Methode nicht möglich ist, zum Beispiel wenn in `up()` einige Tabellenzeilen gelöscht wurden. In diesem Fall wird die Migration irreversibel genannt. Man kann sie also nicht rückgängig machen und die Datenbank in einen früheren Zustand zurückfahren. Das folgende Beispiel zeigt die Migration zum Erstellen einer News-Tabelle. ~~~ [php] class m101129_185401_erstelle_news_tabelle extends CDbMigration { public function up() { $this->createTable('tbl_news', array( 'id' => 'pk', 'title' => 'string NOT NULL', 'content' => 'text', )); } public function down() { $this->dropTable('tbl_news'); } } ~~~ Die Basisklasse [CDbMigration] stellt einige Methoden zum Manipulieren von Daten und DB-Schemas bereit. Mit [CDbMigration::createTable] kann man zum Beispiel eine Tabelle erzeugen, während [CDbMigration::insert] Zeilen in eine Tabelle einfügt. Alle Methoden verwenden die Datenbankverbindung, die von [CDbMigration::getDbConnection()] zurückgeliefert wird. Standardmäßig ist das `Yii::app()->db`. > Info|Info: Sie werden feststellen, dass die DB-Methoden von [CDbMigration] > denen von [CDbCommand] sehr ähneln. Sie sind tatsächlich auch fast > identisch, außer, dass bei den [CDbMigration]-Methoden zusätzlich die > Zeit gemessen, sowie einige Informationen über die Parameter ausgegeben > werden. Migrationen anwenden -------------------- Um alle verfügbaren neuen Migrationen anzuwenden (um die lokale Datenbank also auf den aktuellsten Stand zu bringen) ruft man diesen Befehl auf: ~~~ yiic migrate ~~~ Der Befehl listet alle neuen Migrationen auf. Bestätigt man die Durchführung der Migrationen, werden sämtliche `up()`-Methoden aller neuen Migrationsklassen ausgeführt. Die Reihenfolge entspricht dabei dem Zeitstempel im Klassennamen. Nachdem eine Migration angewendet wurde, speichert das Migrationstool dazu einen Datensatz in einer Tabelle namens `tbl_migration`. Das ermöglicht dem Tool, festzustellen, welche Migrationen schon angewendet wurden und welche nicht. Falls die Tabelle `tbl_migration` nicht existiert, wird das Tool sie automatisch anlegen und zwar in der Datenbank, die in der `db`-Komponente konfiguriert wurde. Manchmal kommt es vor, dass man nur eine oder wenige Migrationen durchführen möchte. Das geht mit diesem Befehl: ~~~ yiic migrate up 3 ~~~ Damit werden 3 neuen Migrationen angewendet. Die Zahl bestimmt also, wieviele Migrationen man anwenden möchte. Man kann die Datenbank mit folgendem Befehl auch auf eine bestimmte Version migrieren: ~~~ yiic migrate to 101129_185401 ~~~ Man gibt also den Zeitstempel-Teil des Migrationsnamen an, um die Version zu spezifizieren, zu der man migrieren möchte. Sämtliche Migrationen zwischen der aktuellen lokalen DB-Version und dem angegebenen Zeitstempel werden somit durchgeführt. Wurde die angegebene Migration bereits durchgeführt, so werden alle späteren Migrationen rückgängig gemacht (siehe unten). Migrationen rückgängig machen ----------------------------- Um die letzte(n) angewendete(n) Migration(en) rückgängig zu machen, kann man folgenden Befehl verwenden: ~~~ yiic migrate down [schritt] ~~~ wobei der optionale `schritt`-Paramter angibt, wie viele Migrationen man rückgängig machen möchte. Standardmäßig steht er auf 1, wodurch die letzte Migration zurückgefahren wird. Wie oben erwähnt, können nicht alle Migrationen rückgängig gemacht werden. Versucht man eine irreversible Migration rückgängig zu machen, wird eine Exception geworfen und der gesamte Prozess beendet. Migrationen wiederholen ----------------------- Migrationen zu wiederholen bedeutet, sie erst rückgängig zu machen und dann erneut anzuwenden. Das geschieht mit diesem Befehl: ~~~ yiic migrate redo [schritt] ~~~ wobei der optionale `schritt`-Parameter wieder angibt, wie viele Migrationen wiederholt werden sollen. Standardmäßig wird auch hier die letzte Migration wiederholt. Anzeigen von Migrationsinformationen ------------------------------------ Das Tool kann nicht nur Migrationen anwenden und rückgängig machen, sondern auch die Historie der durchgeführten Migrationen bzw. die Liste der neuen Migrationen anzeigen. ~~~ yiic migrate history [limit] yiic migrate new [limit] ~~~ Der optionale Parameter `limit` gibt an, wieviele Migrationen maximal angezeigt werden sollen. Wird er weggelassen, werden alle Migrationen angezeigt. Der erste Befehl zeigt alle angewendenten Migrationen, der zweite die Liste der neuen, die noch nicht durchgeführt wurden. Ändern der Migrations-Historie ------------------------------ Es kommt vor, dass man die Migrationshistorie auf eine bestimmte Version setzen möchte, ohne die Migration tatsächlich durchzführen oder zurückzufahren. Gerade wenn man eine neue Migration erstellt ist dies häufig der Fall. Dazu dient der folgende Befehl: ~~~ yiic migrate mark 101129_185401 ~~~ Der Befehl ist ähnlich zu `yiic migrate to`, außer, dass er nur die Migrationshistorie auf die angegebene Version setzt, ohne Migrationen durchzuführen oder zurückzufahren. Anpassen des Migrationsbefehls ------------------------------ Der Migrationsbefehl kann auf verschiedene Arten angepasst werden. ### Über Kommandozeilen-Optionen Der Migrationsbefehl kennt vier Optionen, die an der Kommandozeile angegeben werden können: * `interactive`: boolean, gibt an, ob die Migrationen im interaktiven Modus ausgeführt werden soll, was standardmäßig der Fall ist. Der Anwender wird so vor der Durchführung einer Migration gefragt. Setzt man die Option auf `false` wird die Migration im Hintergrund durchgeführt. * `migrationPath`: string, legt das Verzeichnis mit allen Migrationsdateien fest. Es muss ein Pfadalias angegeben werden, der auf ein existierendes Verzeichnis verweist. Wird nichts angegeben, wird das `migrations`-Unterverzeichnis im Basispfad verwendet. * `migrationTable`: string, gibt den Namen der Tabelle für die Migrationshistorie an. Vorgabewert ist `tbl_migration`. Die Tabellenstruktur ist `version varchar(255) primary key, apply_time integer`. * `connectionID`: string, die ID der DB-Komponenten. Standardmäßig 'db'. * `templateFile`: string, gibt den Pfadalias zu einer Vorlagendatei für neue Migrationsklassen an (z.B. `application.migrations.template`). Wird diese Option nicht angegeben, wird eine interne Vorlage verwendet. Innerhalb des Templates wird der Token `{ClassName}` später mit dem eigentlichen Klassennamen ersetzt. Diese Optionen können wie folgt angegeben werden: ~~~ yiic migrate up --option1=value1 --option2=value2 ... ~~~ Will man zum Beispiel ein Modul `forum` migrieren, dessen Migrationsdateien im `migrations`-Verzeichnis des Moduls zu finden sind, eignet sich dieser Befehl: ~~~ yiic migrate up --migrationPath=ext.forum.migrations ~~~ ### Über globale Konfiguration des Befehls Während man mit den Kommandozeilenoptionen die Migration direkt beeinflussen kann, ist es manchmal einfacher, die Konfiguration einmalig für alle Aufrufe zu verändern. Evtl. möchte man ja eine andere Tabelle für die Migrationshistorie oder eine angepasste Vorlage verwenden. Dazu kann man die Konfiguration für Konsolenanwendungen folgendermaßen anpassen: ~~~ [php] return array( ...... 'commandMap'=>array( 'migrate'=>array( 'class'=>'system.cli.commands.MigrateCommand', 'migrationPath'=>'application.migrations', 'migrationTable'=>'tbl_migration', 'connectionID'=>'db', 'templateFile'=>'application.migrations.template', ), ...... ), ...... ); ~~~ Ruft man nun den `migrate`-Befehl auf, werden obige Optionen immer angewendet, ohne sie explizit mit angeben zu müssen.
$Id: database.migration.txt 2832 2011-01-10 14:37:04Z qiang.xue $