私はそれについてしばらく考えていましたが、これを行うには2つの方法しか考えられません。どちらも、抽象データレイヤー/モデルに作成すると完全に透過的に機能します。
ちなみに、ORMマッパーの教義には「バージョン管理可能な」テーブルデータの実装があります。ドキュメント内のこの
オプションA:リビジョンデータを保持するために各テーブルのコピーを用意する
簡単な連絡先テーブルがあるとします:
CREATE TABLE contact (
id INT NOT NULL auto_increment,
name VARCHAR(255),
firstname VARCHAR(255),
lastname VARCHAR(255),
PRIMARY KEY (id)
)
そのテーブルのコピーを作成し、リビジョンデータを追加します:
CREATE TABLE contact_revisions (
id INT NOT NULL,
name VARCHAR(255),
firstname VARCHAR(255),
lastname VARCHAR(255),
revision_id INT auto_increment,
type ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
change_time DEFAULT current_timestamp,
PRIMARY KEY(revision_id)
)
INSERT
を追跡する およびUPDATE
AFTER
を使用する トリガー。オリジナルの新しいデータリビジョンごとに、新しいデータのコピーをリビジョンテーブルに挿入し、変更のtype
を設定します。 適切に。
DELETE
をログに記録するには 改訂上安全な場合は、履歴テーブルにも新しい行を挿入する必要があります。このためには、BEFORE DELETE
を使用する必要があります 削除される前に、最新の値をトリガーして保存します。それ以外の場合は、すべてのNOT NULL
を削除する必要があります 履歴テーブルにも制約があります。
この実装に関するいくつかの重要な注意事項
- 履歴テーブルの場合、すべての
UNIQUE KEY
を削除する必要があります (ここ:PRIMARY KEY
)データリビジョンごとに同じキーが複数回あるため、リビジョンテーブルから。 -
ALTER
更新(ソフトウェア更新など)による元のテーブルのスキーマとデータは、同じデータまたはスキーマの修正が履歴テーブルとそのデータにも適用されていることを確認する必要があります。そうしないと、レコードセットの古いリビジョンに戻すときに問題が発生します。 - 実際の実装では、どのユーザーがデータを変更したかを知りたいと思うでしょう。その改訂を安全にするために、ユーザーレコードをusersテーブルから削除しないでください。アカウントをフラグで無効に設定する必要があります。
- 通常、1つのユーザーアクションには複数のテーブルが含まれます。実際の実装では、複数のテーブルのどの変更が単一のユーザートランザクションに属し、どの順序で行われるかも追跡する必要があります。実際のユースケースでは、1つのトランザクションのすべての変更を逆の順序で一緒に元に戻す必要があります。そのためには、ユーザーとトランザクションを追跡し、履歴テーブル内のすべての個々のリビジョンとのゆるい関係を保持する追加のリビジョンテーブルが必要になります。
メリット:
- 完全にデータベース内にあり、アプリケーションコードから独立しています。 (ユーザートランザクションの追跡が重要な場合はそうではありません。単一のクエリの範囲外のロジックが必要になります)
- すべてのデータは元の形式であり、暗黙的な型変換はありません。
- リビジョンでの検索での良好なパフォーマンス
- 簡単なロールバック。単純な
INSERT .. ON DUPLICATE KEY UPDATE ..
を実行するだけです。 ロールバックするリビジョンのデータを使用して、元のテーブルのステートメント。
メリット:
- 手動で実装するのは難しい。
- データベースの移行/アプリケーションの更新に関しては、自動化が困難です(ただし不可能ではありません)。
すでに上で述べたように、教義versionable
似たようなことをします。
オプションB:中央の変更ログテーブルを用意する
序文:悪い習慣、代替案の説明のためにのみ示されています。
このアプローチは、データレイヤー/モデルに隠されている必要があるアプリケーションロジックに大きく依存しています。
を追跡する中央の履歴テーブルがあります
- 誰がしたか
- いつ
- 変更、挿入、または削除
- どのデータ
- どのフィールドで
- どのテーブル
他のアプローチと同様に、どの個々のデータ変更が単一のユーザーアクション/トランザクションに属し、どの順序であるかを追跡することもできます。
メリット:
- テーブルにフィールドを追加したり、新しいテーブルを作成したりするときに、元のテーブルと同期を保つ必要はありません。透過的にスケーリングします。
メリット:
- 単純な値を使用する悪い習慣=データベースのキーストア
- 暗黙的な型変換のため、検索パフォーマンスが悪い
- 書き込みロックが原因で中央履歴テーブルがボトルネックになると、アプリケーション/データベースの全体的なパフォーマンスが低下する可能性があります(これは、テーブルロックを備えた特定のエンジン(MyISAMなど)にのみ適用されます)
- ロールバックを実装するのははるかに困難です
- 暗黙的な型変換によるデータ変換エラー/精度の低下の可能性
- モデル/データレイヤーを使用する代わりにコードのどこかでデータベースに直接アクセスする場合、変更を追跡しません。この場合、リビジョンログに手動で書き込む必要があることを忘れてください。他のプログラマーとチームで作業する場合、大きな問題になる可能性があります。
結論:
- オプションB 変更をログに記録するためだけの単純な「ドロップイン」として、小さなアプリに非常に便利です。
- 過去にさかのぼり、歴史的な復讐の違いを簡単に比較できるようにしたい場合 123 リビジョン125 および/または古いデータに戻し、オプションA 行くのは難しい方法です。