36

現在の開発ワークフローでは、データベースの移行(Ruckusingを使用)を導入して、開発者のdbスキーマの同期を維持しています。それはうまく機能し、使用は非常に簡単ですが、データベースのバージョン管理システムで次の問題に直面しているVCSとしてgitに切り替えました。

しばらくの間開発中のブランチをチェックアウトすると、データベーススキーマが元のブランチのスキーマから大幅に逸脱している可能性があります。これにより、データベースの競合が発生する場合があります。論理的には、以前に行っていたブランチに応じて移行を実行する必要があるようですが、それは非常に高速に複雑になる可能性があり、確かに一部の人に問題が発生します。そして、私が知る限り、ブランチ対応のデータベース移行システムはありませんか?

機能ブランチに切り替えると、いくつかの移行を実行する必要があり、他の移行を実行する必要がある場合があります。技術的には、現在のdbmigrationスクリプトを使用すると、これは不可能に思えますが、適切な代替手段はありますか?非常にアクティブで分岐した開発システムでデータベースの移行を処理するための好ましい方法はありますか?

4

5 に答える 5

29

増分移行が腐敗することに私は本当に同意しません。私の意見では、自家製のスクリプトのセットを用意することは、そのような仕事のための実際のツールを用意するよりも悪いアプローチであり、それらの変更の追跡が容易になります。以前は自分で同じような状況に対処しなければならなかったので、いくつかの洞察を共有できることを願っています。

私の経験では、RDBMS-スキーマとブランチはあまりうまく混ざっていません。分岐に応じて、スキーマはおそらく少なくともある程度類似しているはずです。その場合、移行はそれほど異ならないはずです。または、問題の全容を誤解している可能性があります。たとえば、顧客固有のコードをブランチに保持しようとしている場合は、代わりにモジュール化する方法を検討する必要があります。私たちはこのようなことを行い、顧客固有のスキーマが変更され、コードは共通のコードベースにのみ依存することができ、その逆はできないというルールがありました。また、モジュールと日付に基づいてモジュール変更セット間の優先順位を設定したため、ほとんどの部分で、変更が適用される順序がわかっていました。もちろんYMMVですが、現在の設定を知らずに詳細を説明するのは困難です。

私の古い会社では、Liquibaseというツールを使用することに成功しました。これは、使用しているものと似ています。基本的には、DBスキーマ、およびある既知の状態から別の既知の状態へのすべてのデータを取得するためのツールです。liquibaseはチェックサム付きの変更ログを維持するため、同じ変更セットは1回だけ適用されます。変更ログは特定のXML形式で書き込まれます。別の方法が必要な場合は、試してみることを強くお勧めします。

とにかく、顧客コードとブランチを処理する方法は、特定のブランチに特定のDB/スキーマを用意することでした。このようにして、分岐点からスキーマとデータを取得し、差分を現在の状況にのみ移行することができます。理論的にはliquibaseがこれをサポートできたとしても、変更を元に戻すことはしませんでした。これは、非常に面倒でエラーが発生しやすいと感じたためです。liquibaseが独自の状態を維持していることを考えると、移行は常に、特定のブランチで現在の状態を取得し、すべてを適用するのと同じくらい簡単でした。新しいチェンジセットのみが適用され、スキーマは良好な状態のままになりました。

gitのように配布されているmercurialを使用したので、セットアップは非常に似ていました。また、開発用ラップトップには開発者固有のローカルDBがあり、さまざまな顧客とフェーズ(開発、統合、本番)の両方に対応する多数の環境があったため、モデルは実際にテストされ、驚くほどうまく機能しました。チェンジセットでいくつかの競合が発生しましたが、問題が発生した直後にほとんど解決できました。開発中にいくつかのスキーマ変更が導入された可能性があるため、ローカル開発環境は実際に最も困難な部分でした。これは、後の変更セットと常に互換性があるとは限りませんが、変更の構造化された性質と、元に戻してごくわずかになる既知の状態があります。本当の問題。

このアプローチにはいくつかの注意点があります。

  1. スキーマへのすべての変更は、チェンジセットに実装する必要があります。混乱の最大の原因は、いつも誰かが少しいじっているだけでした。
  2. 最初のポイントは、スキーマを変更するツール( HibernateなどのORMツールなど)を使用している場合にも当てはまります。このツールが行う変更と必要な変更を理解するには、このツールにかなり精通している必要があります。
  3. すべてのユーザーはこれに同意し、ルールに従うように教育を受ける必要があります。チェック1。
  4. 多くのチェンジセットの移行に時間がかかりすぎる時期が来ています。この時点で、新しいベースラインを作成する必要があります。これは、特に多くのブランチがある場合は、少し注意が必要です。これについても事前に計画し、少なくとも既存のすべてのDBブランチについて知っておくとよいでしょう。
  5. ある時点でブランチがマスターに戻るかどうかを知るために、ブランチについて少し前もって計画する必要があります。単純なマージは、スキーマの変更ではうまく機能しない可能性があります。
  6. 非常に長寿命のブランチと分離されたデータセットの場合、このモデルは十分に強力ではない可能性があります

ただし、重要なのは、データベースに対する構造と制御が多ければ多いほど、移行が容易になるということです。したがって、Liquibaseのようなツールは、これらの変更を追跡するのに役立つ非常に貴重な資産になる可能性があります。これは、単純なモデルよりもさらに複雑なモデルにも当てはまるため、少なくとも、すでに配置されているすべてのツールをダンプすることを検討しないでください。そして、他の代替ツールを探索するために少し時間がかかります。

いくつかの構造と制御は、何もないよりも優れているか、さらに悪いことに、大量の手動スクリプトで制御していると考えています。

于 2011-06-20T19:57:10.983 に答える
16

インクリメンタルマイグレーションの全体像はかなり腐っていると思います。あなたのような複雑な環境では、それは実際には機能しません。単純なブランチパターンで機能させることもできますが、複雑なものでは悪夢になります。

現在使用しているシステムは別のアプローチを採用しています。段階的な移行を行うことはできませんが、データベースをベースラインから再構築することしかできません。初期開発中、そのベースラインは空のデータベースであり、メンテナンス中は、ライブデータベースのコピーです(ダンプから復元されました)。現在のシステムを取得するためにベースラインに適用するSQLおよびXMLスクリプトの山があります(移行は基本的にですが、段階的に実行するようには設計されていません)。ブランチの更新または切り替えは非常に簡単です。データベースを削除し、ダンプをロードしてベースラインを確立し、スクリプトを実行します。

このプロセスは、いくつかの移行を実行するほど高速ではありませんが、十分に高速です。コーヒーを飲みに行くには十分な時間がかかりますが、昼食をとるには十分な時間ではありません。

大きな利点は、データベースを削除することから始めるということは、プロセスが完全に履歴に依存しないことを意味するため、ブランチの交差や過去への遡りなどを知る必要も気にする必要もないことです。

リリースをライブで取得する場合、明らかに少し異なる方法で処理を行います。システムはすでにベースラインにあるため、データベースを削除したり、ダンプをロードしたりしません(ベースラインはライブシステムの状態として定義されます)。スクリプトを実行するだけです。その後、開発の新しいベースラインとして使用する新しいダンプを作成します。

于 2011-06-20T10:46:56.797 に答える
3

私は、ライブWebサイトと、データベーススキーマを変更する必要があるいくつかの開発ブランチで作業しているのと同じような状況にあります。

gitでうまく使用できるpost-checkoutとpost-mergeフックを書くことでそれを解決しました。すべての移行をSQL​​ファイルの形式で別のディレクトリに保存し、変更されたPHPコードと一緒にコミットします。私が実行するたびに

git checkout

または

git merge

gitは、適切なアップマイグレーションとダウンマイグレーションを自動的に呼び出します。Githubでの私の実装を参照してください。

特別なリクエストとして(githubリンクをたどりたくない人のために)もう少し説明:

次のシナリオを考えてみましょう。2つのブランチがあります。

  • マスター-現在オンラインになっているWebサイトが含まれています
  • 機能-未完成の新機能が含まれています

新機能を正しく機能させるには、データベーススキーマを変更する必要があります。ワークフローは次のとおりです。

  1. 機能ブランチで、データベーススキーマの変更が必要なコードを変更すると、移行ディレクトリに2つの新しいSQLファイルもコミットされます。

    • 20151120130200-extra-field-up.sql(上位に移行するためのすべてのSQLクエリを含む)
    • 20151120130200-extra-field-down.sql(すべてのSQLクエリを含む)
  2. マスターへのチェックアウトを実行すると、受信後のgitフックは次のようになります。
    1. からのコミットですべての*-down.sqlスクリプトを検索します<new HEAD>..<old HEAD>
    2. ローカルデータベースでこれらのスクリプトを実行する
    3. からのコミットですべての*-up.sqlスクリプトを検索します<old HEAD>..<new HEAD>
    4. ローカルデータベースでこれらのスクリプトを実行する
  3. 機能ブランチをマスターにマージすると、マージ後のフックは次のようになります。
    1. からのコミットですべての*-up.sqlスクリプトを検索しますmaster..feature
    2. ローカルデータベースでこれらのスクリプトを実行する

インストール

チェックアウト後および/またはマージ後のファイルを、独自のgitリポジトリの.git/hooksディレクトリにコピーするだけです。これらのファイルの構成セクションを編集できます。説明については、ファイル自体を参照してください。

使用法

移行SQLファイルの命名は非常に重要です。up.sqlまたはで終わる必要があり down.sqlます。名前の残りの部分は完全にあなた次第です。ただし、複数のアップマイグレーションおよび/または複数のダウンマイグレーションを伴う単一のコミットがある場合、それらが実行される順序は辞書式順序によって異なります。異なるコミット内にある移行ファイルは、常にコミットと同じ(逆の)順序で呼び出されます。

アップマイグレーションとダウンアップグレードの両方がある必要はありません。また、アップマイグレーションとダウンマイグレーションの名前が同じである必要もありません。

于 2015-11-21T10:12:37.080 に答える
1

現在のプロジェクトでテストすることを考えているアプローチは、ブランチ「移行」を作成することであり、すべての(そして唯一の)移行はこのブランチにコミットされます。開発者は、移行を作成する前に、このブランチから現在のブランチにマージして、移行が常に最新の移行の上に作成されるようにする必要があります。すべてのプロジェクトはこのブランチからマージされるため、すべてのブランチには線形移行履歴の概念があります。これにより、すべてのブランチがデータベースバージョン間を行き来することができます。データベースの異なるバージョンに依存するブランチに切り替える場合、開発者は適切な移行を適用します。

煩わしさ(特別なブランチへの移行をコミットするための余分な作業と勤勉さを除いて)は、どの移行が特定のブランチに対応するかを覚えています。これを行う1つの方法は、移行を直接移行ブランチにコミットする代わりに、移行(および移行のみ)を現在のブランチにコミットしてから、そのコミットを移行ブランチにチェリーピックすることだと思います。次に、現在のブランチが移行ブランチにチェリーピックされた最後の時間を見て、その差分に必要な移行が含まれていることを確認できます。それは可能だと思います。また、開発者は、必要な変更を確認するためだけに移行を作成してから、どの移行を使用するのが適切かを推測しようとする場合があります。

漠然とした提案でごめんなさい。このアプローチを試してみることになった場合は、この提案をより具体的な推奨事項で編集します。

于 2013-03-01T09:04:50.817 に答える
0

これは私が最近取り組んでいることです。私にとって問題は、データベーススキーマ自体が分岐していることではなく、むしろgitがそれらをマージできないことです。データベーススキーマに接触する機能ブランチは常に怖いです。

私が考えていた解決策は、線形移行ではなく、他の移行に依存する移行を行うことです。線形化(トポロジカルソート)するのに十分簡単な、移行の優れた依存関係グラフが得られます。データベース内の名前付き移行を追跡し、正しい順序で、まだ更新されていない更新を実行するだけです。

たとえば、にaddCustomerSalt依存しinitialSchema、にseparateAddress依存しpersonます。

これで解決できない問題の1つは、ブランチAがブランチBで作成された更新Zに依存している場合ですが、その場合は、共通の祖先にリベースする必要がありますか?

于 2012-08-15T08:56:41.050 に答える