3

トランザクションデータベースを使用して、ユーザーフレンドリーなインターフェイスのundoプロパティを実装する方法がわかりません。

一方では、ここで回答に記載されているように、ユーザーにはマルチレベル(無限)の取り消しの可能性があることをお勧めします。この問題に役立つ可能性のあるパターンは、Memento またはCommandです。

ただし、トリガー、増え続けるシーケンス番号、元に戻せない手順などの複雑なデータベースを使用すると、トランザクションの境界とは異なるポイントで元に戻すアクションがどのように機能するかを想像するのは困難です。つまり、最後にコミットされたトランザクションが単なるロールバックである時点まで元に戻しますが、どのようにして別の瞬間に戻ることができますか?

更新(これまでの回答に基づく):変更が既にコミットされているときに元に戻るが機能することを必ずしも望んでいません。トランザクションが開いている実行中のアプリケーションに焦点を合わせます。ユーザーが[保存]をクリックするたびにコミットを意味しますが、保存する前に(同じトランザクション中に)元に戻るが機能するはずです。データベースを永続層として使用することは単なる実装の詳細であり、ユーザーはそれを気にする必要がないことを私は知っています。しかし、「データベースとGUIで元に戻すという考え方は根本的に異なる」と考え、データベースで元に戻るを使用しない場合、無限の元に戻すは単なる流行語にすぎません。「ロールバックは...ユーザーによる取り消しではない」ことを私は知っています。

では、同じトランザクション内で「変更の結果としてのカスケード効果」を考慮して、クライアントレベルの取り消しを実装するにはどうすればよいでしょうか。

4

5 に答える 5

6

データベースと GUI での元に戻すという考え方は、根本的に異なるものです。GUI はシングル ユーザー アプリケーションになり、他のコンポーネントとの相互作用が少なくなります。データベースはマルチユーザー アプリケーションであり、変更の結果として、変更がカスケード効果を持つ可能性があります。

やるべきことは、ユーザーが以前の状態を新しいトランザクションとして試して適用できるようにすることです。これは機能する場合と機能しない場合があります。あるいは、コミット後に元に戻す操作を行わないでください (保存後に元に戻す操作を行わないのと同様で、これは多くのアプリケーションでオプションになっています)。

于 2009-01-13T10:28:45.137 に答える
4

一部の (すべて?) DBMS は、部分的なロールバックを可能にするセーブポイントをサポートしています。

savepoint s1;
insert into mytable (id) values (1);
savepoint s2;
insert into mytable (id) values (2);
savepoint s3;
insert into mytable (id) values (3);
rollback to s2;
commit;

上記の例では、最初の挿入のみが残り、他の 2 つは元に戻されます。

あなたが与えた理由*やおそらく他の理由から、コミット後に元に戻すことは一般的に実用的ではないと思います。一部のシナリオでそれが不可欠な場合は、それを行うために多くのコードを作成し、トリガーなどの影響を考慮する必要があります.

  • しかし、増加し続けるシーケンスに問題はありませんか?
于 2009-01-13T10:24:18.280 に答える
2

データに適用されたすべてのトランザクション (実際にはすべてではなく、3 か月未満のトランザクションのみ) を追跡することにより、データベースでそのような可能性を開発しました。基本的な考え方は、誰がいつ何をしたかを確認できるようにすることでした。GUID によって一意に識別される各データベース レコードは、1 つの INSERT、複数の UPDATE ステートメント、および最後に 1 つの DELETE ステートメントの結果と見なすことができます。これらすべての SQL ステートメントを追跡し、INSERT はグローバル INSERTS であるため (すべてのフィールド値の追跡が INSERT ステートメントに保持されます)、次のことが可能になります。

  • 誰がどのフィールドをいつ変更したかを把握する: ポールがプロフォーマ インボイスに新しい行を挿入した、ビルが商品の単価を再交渉した、パットが最終注文数量を変更した、など)
  • 次のルールを使用して、以前のすべてのトランザクションを「元に戻す」:

    'INSERT' 取り消しは、一意の識別子に基づく 'DELETE' です。

    「UPDATE」の取り消しは、前の「UPDATE」と同等です

    'DELETE' 取り消しは、最初の INSERT とそれに続くすべての更新に相当します。

  • 3 か月以上前の取引は追跡しないため、UNDO は常に利用できるわけではありません。

これらの機能へのアクセスは、データベース マネージャーのみに厳密に制限されています。他のユーザーは、ビジネス ルールの範囲外でデータを更新することは許可されていません (例: 発注書が一度承認された場合、発注書明細の「元に戻す」とはどういう意味ですか)。サプライヤーによって同意されていますか?)実を言うと、このオプションを使用することはほとんどありません (年に数回?)。

于 2009-01-13T10:35:10.960 に答える
2

これは William の投稿 (私が実際に投票したもの) とほぼ同じですが、(データベースのロールバックを使用するのではなく) ユーザーの取り消しを実装する必要がある理由をもう少し詳しく説明します。

あなたのアプリケーションについてもっと知ることは役に立ちますが、ユーザーにとって(フレンドリーな)元に戻す/やり直すには、データベースは機能を実装するのに適切なレイヤーではないと思います.

  1. ユーザーは、実行したアクションを元に戻したいと考えています。これらのアクションがデータベース トランザクションを発生させないか、1 つ以上発生させるかは関係ありません。
  2. ユーザーは自分が行った操作を元に戻したいと考えています (他の人の操作ではありません)。

私の観点から見たデータベースは実装の詳細であり、プログラマーがデータを保存するために使用するツールです。ロールバックは、ユーザーが元に戻すのに役立つ一種の元に戻す機能です。ユーザーが元に戻す操作ではありません。ロールバックを使用することは、ユーザーが知りたくないことや理解していないこと (および理解する必要がないこと) にユーザーを巻き込むことを意味し、これは決して良い考えではありません。

William が投稿したように、セッションの一部としてクライアント内またはサーバー側に実装が必要です。これは、ユーザー トランザクションとして定義したステップを追跡し、これらを元に戻すことができます。これらのユーザー トランザクション中にデータベース トランザクションが行われた場合は、これらを取り消すために他のデータベース トランザクションが必要です (可能な場合)。元に戻すことができない場合は、必ず貴重なフィードバックを提供してください。これは、データベースではなくビジネスについて説明することを意味します。

于 2009-01-13T11:17:59.763 に答える
1

以前のセマンティクスへの任意のロールバックを維持するには、データベースに論理的な削除を実装する必要があります。これは次のように機能します。

各レコードには、再構築をどの程度巧妙にする必要があるかに応じて、「削除済み」フラグ、バージョン番号、および/または「現在のインジケーター」フラグがあります。さらに、どのレコードがどの特定のエンティティを実際に参照しているかを知るために、そのエンティティのすべてのバージョンにわたってエンティティごとのキーが必要です。バージョンが適用された時間を知る必要がある場合は、'From' 列と 'To' 列を使用することもできます。

レコードを削除すると、「削除済み」としてマークされます。変更する場合は、新しい行を作成し、古い行を更新して古い行を反映させます。バージョン番号を使用すると、ロールバックする前の番号を見つけることができます。

参照整合性が必要で (不要だと思っていても、おそらく必要です)、余分な I/O に対処できる場合は、すべてのバージョンでレコードのプレースホルダーとしてキーを持つ親テーブルも必要です。

Oracle では、クラスター化されたテーブルがこれに役立ちます。親テーブルとバージョン テーブルの両方を同じ場所に配置できるため、I/O のオーバーヘッドが最小限に抑えられます。SQL Server では、キーを含むカバリング インデックス (エンティティ キーでクラスター化されている可能性があります) により、余分な I/O が削減されます。

于 2009-01-13T11:23:43.903 に答える