2

私のシナリオでは、ユーザーがサーバーにリクエストを送信すると、サーバーはアイテムのリストをデータベースにアップロードできます。アイテムのリストは、いくつかのクエリで構成される for ループでデータベースにアップロードされます。これらの項目を順番にデータベースに追加することが非常に重要です。

問題は、ユーザーが別のリクエストを発行すると、別の一連の for ループが起動され、項目が正しい順序でデータベースに追加されない可能性があることです。(データベースに項目を追加する for ループが 2 つあるため)。

例: リクエスト 1: 1,2,3 リクエスト 2: 4,5,6 データベースに挿入される順序: 1,2,3,4,5,6 4,2,5,6,3

別のユーザーが要求を発行した場合、2 つの要求は相互に排他的であるため、問題はありません。

この問題を解決するには、静的メソッドを使用するか、synchronized キーワードを使用しますが、コードでボトルネックを引き起こしたくありません (他のユーザーがデータベースへのアクセスを待つ必要はありません!)。

または、for ループを使用して複数のクエリを実行するのは悪い考えでしょうか?

オブジェクトやメソッドではなく、「リクエスト」に基づいてコードを同期するにはどうすればよいですか? デザインパターンとかあるの?

4

5 に答える 5

0

Queueデータベースに挿入するには、一連のリクエストを行う必要があるようです。そうすれば、すべてのクエリが必要な順次形式で実行されます。

ただし、これを正しく行うには、別のスレッドでこれを行う必要があります (データベース トランザクションが頻繁にブロックされたり、非常に遅くなったりする可能性があるため、実行することをお勧めします)。

このソリューションは「ロック」を必要とせず、スレッド化により応答性が高くなりますが、線形性の必要性は維持されます。

于 2013-05-30T20:44:02.710 に答える
0

複数のアプリケーション サーバーが問題にならない場合は、StripedLock を検討してください。制限された数のロックのみを作成しながら、ID で同期できます。

https://code.google.com/p/guava-libraries/wiki/StripedExplained

private static Striped<Lock> STRIPPED_LOCK = Striped.lazyWeakLock(64);
try {
    STRIPPED_LOCK.get(id).lock();
    ....stuff....
} finally {
    STRIPPED_LOCK.get(id).unlock();
}

あなたの場合、IDにセッションID(文字列)を使用できます。

于 2013-05-30T20:44:08.003 に答える
0

ここに全体像はありませんが、「ユーザーが別のリクエストを発行した」と言うので、最初のリクエストが完了するのを待たないということでしょうか?

その場合、「コマンド」パターンを検討できます。クエリはキューに入れられるオブジェクトで表され、プログラムは一度に 1 つずつキューから処理します。キュー内の各オブジェクトは、その処理を表す「コマンド」です。

于 2013-05-30T20:45:15.690 に答える
0

最善ではないかもしれませんが、私があなたの状況にある場合は、分離されたバッチで分離されたキュー内プロセスで行います。

例: キューと詳細の 2 つのテーブルがあります。

List_Queue(
    id int identity not null primary key,
    user_id varchar(xx),
    is_processable tinyint default 0,
    is_processing tinyint default 0,
    is_processed tinyint default 0,
)

List_Queue_Detail(
    queue_id int,
    // your rest of data,
    inserted_timestamp datetime
)

List_Queueユーザーが送信するたびに、テーブルが挿入されます。次に、あなたの例では、キューテーブルにこの種のレコードがある可能性があります:

11, user01, 0, 0
12, user01, 0, 0

トランザクションはキュー詳細テーブルに挿入されます。次のようにソートされていない場合があります。

11, 1, '01.001'
11, 2, '01.021'
12, 4, '01.032'
12, 5, '01.044'
11, 3, '01.055'
12, 6, '01.061'

秒とミリ秒のタイムスタンプに注意してください。ここで通常の日時を使用できます。

これで、キュー詳細テーブルへの挿入が完了しました。キューの状態が次のようになっているとします。

11, user01, 0, 0, 0
12, user01, 1, 0, 0

プロセス 12 は 11 よりも早く完了します。これは通常のシナリオです。これで、バッチ (おそらく毎分実行される) は「is_processed = 0 で最小のキュー ID」を取得するため、次のようになります。

11, user01, 0, 0, 0

そして、それはリクエストを処理しません。処理可能であれば、キューの詳細を実際のトランザクション テーブルに挿入することができます。is_processing挿入を開始するときにリクエストをマークすることを忘れないでください。

于 2013-05-31T03:27:14.710 に答える