1

他のテーブルで発生した変更を記録するデータベース テーブルがあります。私のログテーブルのテーブル構造は次のとおりです。

    Log_Table(id, table_name, operation, flag)
    values   (1,  Customer_Table, 1,       1);
    values   (2,  Customer_Table, 2,       1);
    values   (3,  Customer_Table, 1,       1);
    values   (4,  Customer_Table, 2,       1);
    values   (5,  Customer_Table, 1,       1);

次の操作を実行して、Web ページのボタンに対してこのテーブルを更新します。

/* first */
public List<Long> select_Changes()
{
    select id from Log_Table where flag =1;
}

/* (wait for user input) */

/* second */
public void update_table(List<Long> ids)
{
    update Log_Table set flag =0 where id in( ids)
}

問題は、最初の操作と 2 番目の操作の間でユーザーが操作を実行することです。その間、別のユーザーが同時に同じ操作を行います。最初のユーザーによって既に選択されている行が 2 番目のユーザーによって選択されることは望ましくありません。つまり、2 番目のユーザーが最初のステップを実行すると (最初のユーザーが実行してからさらに 2 つの行が追加されたと仮定)、結果は次のようになります。

    values(6,Customer,2,1);
    values(7,Customer,1,1);

私が何をすべきか提案してください。行が選択された後、あらゆる種類の操作のために行をロックする必要があります。select for update 句を試しましたが、問題は解決しませんでした。それはWebアプリケーションにあります。

4

2 に答える 2

1

ユーザー入力を待っている間、データベース トランザクションを開いたままにしておくことは、ほとんど良い考えではありません。トランザクションが保留されている間にユーザーが昼食に出かけた場合、またはネットワーク接続がダウンして何日も復元されなかった場合はどうなるでしょうか?

また、使用しているデータベース製品についても言及していません。SELECT FOR UPDATE製品、その構成、およびトランザクションの分離レベルに応じて、トランザクションが保留中の同時実行の結果が試行されるため、移植可能な動作が必要な場合は、動作またはさらに標準化された機能に依存することはできません。

ユーザーの確認を待っている保留中の行を識別する方法を行に提供することをお勧めします。、、、などを表すために、flag列に3 つの状態を使用できます。ただし、ユーザーに表示されたが、ユーザーが [OK] または [キャンセル] (またはオプションが何であれ) をクリックしなかった行を認識する何らかの方法が必要になる場合があります。その目的でタイムスタンプ列を追加する場合、列の 2 つの状態を維持し、最初のステップで次のようなものを使用できます (句をサポートするデータベースを使用していると仮定します)。availablependingtakenflagRETURNING

public List<Long> select_Changes()
{
    UPDATE Log_Table
      SET when_presented = CURRENT_TIMESTAMP
      WHERE flag = 1
        AND when_presented = NULL
      RETURNING id, when_presented;
}

2 番目のステップは次のように変更されます。

public void update_table(List<Long> ids)
{
    UPDATE Log_Table
      SET flag = 0
      WHERE id IN (ids)
        AND when_presented = time_claimed;
}

2 番目のステップは必ずしも変更する必要はありませんが、上記の変更により、別のRETURNING句を使用して、このユーザーが実際に要求した値を確認し、メンテナンス プロセスが放棄されたように見える行セットに戻っidた場合に存在する競合状態を閉じることができます。その後、最初のユーザーが遅ればせながらそれらを要求しようとする直前に、別のユーザーに提示されました。when_presentedNULL

于 2012-12-23T15:53:09.017 に答える
0

タイムスタンプ列と、構造を持つ追加のテーブルを追加しました

Last_Oeration_Time(id number, last_op_time timestamp(6)) 

最初のユーザーがボタンをクリックすると、insert int Last_Oeration_Time(id,last_op_time) values(seq_lasst_op_time_id.nextval,sysdate) のような Last_Oeration_Time で SQL 挿入クエリを実行します

2 番目のユーザーが最初のステップを実行すると (最初のユーザーが実行してからさらに 2 つの行が追加されたと仮定します)、結果は望ましい結果になります。これでよろしいですか?

于 2012-12-23T20:05:16.350 に答える