私はそれについてしばらく考えていましたが、これを行うには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つのトランザクションのすべての変更を逆の順序で一緒に元に戻す必要があります。これには、ユーザーとトランザクションを追跡し、履歴テーブル内のすべての個々のリビジョンとのゆるい関係を保持する追加のリビジョンテーブルが必要になります。
利点:
- アプリケーションコードから独立して、完全にデータベースにあります。(ユーザートランザクションの追跡が重要な場合はそうではありません。単一のクエリの範囲外のロジックが必要になります)
- すべてのデータは元の形式であり、暗黙的な型変換はありません。
- リビジョンでの検索で良好なパフォーマンス
- 簡単なロールバック。
INSERT .. ON DUPLICATE KEY UPDATE ..
ロールバックするリビジョンのデータを使用して、元のテーブルで簡単なステートメントを実行するだけです。
メリット:
- 手動で実装するのは難しい。
- データベースの移行/アプリケーションの更新に関しては、自動化するのは困難です(不可能ではありません)。
すでに上で述べたように、教義versionable
は似たようなことをします。
オプションB:中央の変更ログテーブルを用意する
序文:悪い習慣、代替案の説明のためにのみ示されています。
このアプローチは、データレイヤー/モデルに隠されている必要があるアプリケーションロジックに大きく依存しています。
あなたは追跡し続ける中央の履歴テーブルを持っています
- 誰がした
- いつ
- 変更、挿入、または削除
- どのデータ
- どの分野で
- どのテーブルの
他のアプローチと同様に、どの個々のデータ変更が単一のユーザーアクション/トランザクションに属し、どの順序であるかを追跡することもできます。
利点:
- テーブルにフィールドを追加したり、新しいテーブルを作成したりするときに、元のテーブルと同期を保つ必要はありません。透過的にスケーリングします。
メリット:
- 単純な値を使用する悪い習慣=データベースのキーストア
- 暗黙的な型変換のため、検索パフォーマンスが悪い
- 書き込みロックが原因で中央履歴テーブルがボトルネックになると、アプリケーション/データベースの全体的なパフォーマンスが低下する可能性があります(これは、テーブルロックを備えた特定のエンジン(MyISAMなど)にのみ適用されます)
- ロールバックを実装するのははるかに困難です
- 暗黙の型変換によるデータ変換エラー/精度の低下の可能性
- モデル/データレイヤーを使用する代わりに、コードのどこかでデータベースに直接アクセスする場合、変更を追跡しません。この場合、リビジョンログに手動で書き込む必要があることを忘れてください。他のプログラマーとチームで作業する場合、大きな問題になる可能性があります。
結論:
- オプションBは、変更をログに記録するためだけの単純な「ドロップイン」として、小さなアプリに非常に便利です。
- 過去にさかのぼって、過去のリビジョン123とリビジョン125の違いを簡単に比較したり、古いデータに戻したりしたい場合は、オプションAを使用するのは難しい方法です。