Doctrine:symfonyでの移行の経験

知らない人にとって、移行はデータベース構造を変更する方法です。

さまざまな方法で変更を管理できますが、すべては構造を変更するための指示を操作することになります。



移行がこれを最適な方法で行う理由:

1. オートメーション 。 SQLファイルに指示を保存し、必要に応じてロールできます。 しかし、すべての開発者がテスト環境をデプロイするために変更をロールする必要がある場合、チーム開発のために異なるリビジョン(データベースのバージョン)を切り替える問題が発生した場合、これは非常に不便になります。

2. ロールバック (最初の段落の続きとして)。 移行をロールバックして、いつでもデータベースバージョンを取得できます。 便利なものは、以下を参照してください。

3.データベース DEVおよびPRODバージョンのID 。 少なくとも私にとっては、バージョンDEV、PROD、TESTが完全に同じであることを確認することが非常に重要です。 はい、これは他の方法でも実現できます。 ただし、移行がデータベースの構造に関する情報のキャリアであり、自動化されている場合、この問題を解決することははるかに便利で簡単になります。



基本的なことは説明しませんが、次のことがわかります。

プロジェクトの開始



開発プロセス中に新しいプロジェクトを開始すると(まだベースがありません)、移行を使用してテーブルを作成することを好みます。 一方で、これは少し簡単に行うことができます-回路からベースを作成します。 そして、それに応じて、PRODの最初のリリースを同様の方法で展開します。 しかし、一方で、最初のリリースでの作業は停止せず、データベース構造に新しい変更を加える必要がある瞬間が常にあります。 この場合、移行の初期構造を修正する必要があります(以下を参照)。 したがって、2つのアプローチを切り替えるよりも、どちらかを選択しました。



さらに、データベース(移行なしで継承または開発)が既にある場合は、移行時にその構造を修正します。

これを行わずに既存のデータベースの最初の移行を記述すると、将来的には多くの問題が発生します。 これは、プロジェクトの展開、テスト用のクリーンなベースの作成、およびリビジョン間の切り替えに関する不快な問題です。

一般に、2つのアプローチを組み合わせてはいけません。移行による構造管理とその他のオプションです。



ベースが継承される場合、高い確率で、教義は同一のデータベースを作成するためのスキームと移行を生成できません。 テーブル宣言では、エンジン固有の命令が使用される場合があり、予約語が発生する場合があります。



したがって、同一の状態を修正するために、rawダンプ構造を含む最初の移行を作成しています。 $ this-> rawQuery( "CREATE TABLE ...")のようなもの

これを行うことで、100%のIDを実現し、新しい移行を実行するときに、DEV、PROD、およびTESTのデータベースバージョンが同じであり、テストがPRODにポンプされるまさにその構造で動作することを常に確信しています。

エクスポートの際に教義が行うように、他のすべての人からそれを分離し、大量のファイルを作成しないために、すべての指示を1つの移行に入れます。

結果は、すべてを考慮に入れた1つの簡単な出発点です。



移行の書き方



移行はアトミックでなければなりません

1回の編集-1回の移行。 もちろん、狂信的ではありません。

なんで? 大きな移行(テーブル、キー、データ編集)を1つ作成した場合、突然クラッシュします(たとえば、継承されたデータベースの異なるintを持つキーにFKを作成したり、参照整合性が壊れたときにFKを作成したりするなど)。 その後、いくつかの変更が行われ、いくつかの変更が行われない状況になります。 どの部分を探すべきか。 移行番号が変更されていないため、ロールバックできません。 したがって、ペンですべてをロールバックするには、落ちた場所、既に変更されているもの、変更されていないものを探す必要があります。 または、ロールバックですべてをロールバックできる場合は、移行番号を手動で変更できます。 状況が許せば、データベースをクラッシュさせ、移行をエラーのあるものにロールし、そこに何が落ちたかを理解することはまだ可能です。

一般的に、確率と可能なアプローチについて話す方法はわかりません。アトミックマイグレーションと悲嘆をします。 何かが落ちた場合、タンバリンと踊らずにすぐに診断され、修正されます。



お名前

ファイルの名前と移行クラスで、バージョン番号、モデル、アクション、および説明を示します。
     001_Article_CreateTable.php
     002_Article_AddColumn_AuthorId.php
     003_Article_AddFk_Authors.php
     004_Article_UpdateColumn_Title.php
     005_Article_DropTable.php
        クラス:
    クラスMigration001_Article_CreateTable
このアプローチにより、特定のモデルのすべての移行をすばやく検索/フィルタリングできます。

同様の移行を見つけてコピーアンドペーストして、新しい同様の移行を作成すると便利です。



シリアル番号を使用します。 教義は、私たちが移行と呼ぶものを気にしません。

たとえば、移行ジェネレータはタイムスタンプを置き換えます。 主なものはアルファベット順です。

データベースのバージョン番号と一致するようにシリアル番号を使用しています。

というのは、名前が1と100の2つの移行を記述する場合、データベースのバージョン番号は2になるためです。

混乱したくありません。



確かに、このアプローチでは、さまざまなブランチでの移行作業中に特定の不便さが生じます。 3つの移行があり、2人の開発者がブランチに1つずつ追加する場合、合併中に「4」という名前の2つの移行があります。

これまでのところ、私は唯一の解決策を持っています:

*ブランチをマージするとき、マイグレーションを別のコミットとして名前変更し、リポジトリのクリーンさのために、特定のマイグレーションの編集を1つのコミットに結合します。

したがって、各移行は個別のコミットとして発行することを常にお勧めします。

後で1つの移行のすべてのコミットを結合できるように(1つの問題を解決する一環として)

*また、移行中に明らかに大きなインデックスを持つ一時的な名前を付けることができます。これは、それらがマージ中に名前が変更されることを前提としています。

PS短いブランチがあり、それらをリベースとマージします(git help rebase)



移行()

可能であれば、migrate()とともに短いエントリを使用します。 これは便利で信頼できます-誰も()を書き留めてエラーを犯すことを忘れないでしょう。



ロールバック

私は常に移行をロールバックする機会を残しています。 「不可逆的な」移行であっても。 PRDOへのロールバックに到達したことは一度もありません(または、まだ完了していません)が、リビジョン間の切り替えにはロールバックが主に重要です。

理論的には、データベースが空の場合、任意のリビジョンに切り替えて、移行から現在の構造を上げることができます。 しかし、開発用のデータベースには、フィクスチャから取得できない貴重なデータが存在することがあります。 この場合、ロールバックは不可欠です。 そして、特に異なるデータベース構造を持つ異なるブランチ間で1日に10回切り替える場合は、毎回ダンプを台無しにしたくありません。

したがって、不可逆的な移行はありません。 テーブルまたは列を削除する場合、ロールバックで作成します。 この場合、削除されたデータはもはや重要ではありません。主なことは、移行チェーンを混乱させないことです。そのため、いつでも最初から最初に戻ることができます。

したがって、私は常にロールバックを書いてテストします(--up; --down; --up)。 そして、それらが落ちることが起こります。



データ移行

データの移行とは、データベースの構造に関係しない変更を意味します。 つまり ルックアップテーブルへの行の追加、行の削除、構造の変更後の情報の更新。



最初に、私はこれらの変更を定期的な移行の一環として書き始め、Ryan Weaverと同じレーキにぶつかりました(最後のリンクを参照)。 50から100に移行するときに、51の移行で既に削除または変更されたモデルが使用される(つまり、現在のリビジョンの状態が異なる)と、移行は失敗します。 そして、それをロールするには、目的のリビジョンにロールバックし、モデルを再構築する必要があります。

これはすべて間違っているように思えたので、移行のフレームワークでデータの変更を拒否することにしました。 移行はデータベーススキーマの変更に過ぎず、それ以上の変更ではないと判断しました。 データの移行は、データが存在するPRODでのみ必要であり、テストや開発者には必要ないと考えました。 また、参照フィクスチャはymlを介してアップロードすることもできます。

しかし、実践が示しているように、これは不快であることが判明しました。 データの移行も、ハンドルによってロールされるどこかに修正する必要があります。 また、開発者は仕事が不便だと感じました。



その結果、移行はデータベースの構造とデータを管理するための便利なエントリポイントの1つであるという結論に達しました。 特にチーム開発で。

そのため、現在のリビジョンに依存するモデルを使用しないように、事前/事後フック、そして最も重要なことには純粋なSQLでの定期的な移行でデータ移行を記述します。

さらに、移行時にフィクスチャディレクトリを保存/制御することが非常に便利であることが判明しました。



移行を開始する



移行を1つずつロールします

一般に、この教義では、アップグレードする必要があるデータベースのバージョン番号を指定できます。 移行が検証され、すでにパスを踏んでいる場合は、問題はありません。 ただし、まだ実行されていない場合、またはPRODを使用している場合は、一度に1つずつ実行する必要があります。
     ./symfonyのドクトリン:migrate --up
なぜなら、たとえばバージョン2から10に一気に更新すると、何らかの移行(どのバージョンかはわからない)があるため、バージョン番号は更新されず、実際の番号は5であっても2のままになるためです。落ちた移行を見つけ、データベースのバージョン番号を編集して、移行をロールバックして修復する必要があります。

また、落ちた移行がアトミックではなく、データベースに削除できない貴重なデータがある場合は、非常に不運です。

したがって、PRODでは、常に心を沈めて1つずつロールします。 そして、私はデータベースの同様のコピーで事前にテストしています。



テスト

テストの完全なセットを実行するには、移行からクリーンなデータベースを作成します。
     $ task = new sfDoctrineBuildTask(新しいsfEventDispatcher、新しいsfFormatter);
     $ task-> run($ args = array()、$ options = array(
         'env' => 'test'、
         'no-confirmation' => true、
         'db' => true、
         'and-migrate' => true、
     ));
これにより、TESTとPRODの100%の同一性を実現します。 さらに、新しい移行を考慮して、アプリケーションの動作を間接的にテストします。



その他



ゼロ化移行

私はこのアイデアに興味がありました-すべての移行を削除することが時々ありましたが、そのほとんどはすでに冗長になり、テスト環境を作成するのに多くの時間が必要です。 最初のインポート用に最初の移行を再度記述し、データベース内の移行番号を変更できます。

確かに、私はまだ試していませんし、これがプロジェクトのさまざまなリビジョンでの作業にどのように影響するかわかりません。





トピックに関する同様の考え:Ryan Weaver

http://www.slideshare.net/weaverryan/the-art-of-doctrine-migrations



All Articles