の代わりに、すぐにメモリ内に保留中のメッセージのリストを維持し、キューからそれらを取った後、DBにメッセージをプッシュ。 AまたはBを取得したら、一致するものがリストにあるかどうかを確認します。そうであれば、データベースに正しい順序で両方を提出し、一致するものをリストから削除します。それ以外の場合は、新しいメッセージをそのリストに追加するだけです。
試合をチェックした場合は、シリアル化するタスクあまりにも高価である - 私はあなたが理由でマルチスレッドされていると仮定 - あなたは別のスレッド処理にリストを持つことができます。既存の複数のスレッドを読み込み、直ちにほとんどのメッセージをDBに提出するが、(スレッドセーフ)リストにAsとBsを入れておく。バックグラウンドスレッドは、一致するAsおよびBsを見つけるリストを清掃し、見つかったときに正しい順序でサブミットします(リストから削除します)。
一番下の行です - あなたが複数のスレッドでキューから項目を削除するので、あなたは順序を保証するために、どこかにシリアル化する必要があるとしています。トリックは、シリアルコードでロックした時間と長さを最小限に抑えることです。
また、あなたはそれがこのような状況を検出したときのエントリの順序を変更するために、トリガか何かで、データベースレベルで行うことができます何かがあるかもしれません。私はそこで助けるためにDBプログラミングについて十分に知りません。
UPDATE:メッセージに「A」というメッセージを適切な関連メッセージ「B」を関連付けることができると仮定すると、次のコードはAがBの前にデータベースに入ることを確認します。それらがデータベース内の隣接するレコードであることを確認します - AとBの間に他のメッセージが存在する可能性があります。また、何らかの理由で他のタイプの一致メッセージを受け取らずにAまたはBを取得した場合、比類のないメッセージに永遠に。
は(あなたは、単一のサブルーチンにそれらの2つの「lock'edブロックを抽出することができますが、私はAとBに関して明確にするため、このようにそれを残している)あなたがしている場合は
static private object dictionaryLock = new object();
static private Dictionary<int, MyMessage> receivedA =
new Dictionary<int, MyMessage>();
static private Dictionary<int, MyMessage> receivedB =
new Dictionary<int, MyMessage>();
public void MessageHandler(MyMessage message)
{
MyMessage matchingMessage = null;
if (IsA(message))
{
InsertIntoDB(message);
lock (dictionaryLock)
{
if (receivedB.TryGetValue(message.id, out matchingMessage))
{
receivedB.Remove(message.id);
}
else
{
receivedA.Add(message.id, message);
}
}
if (matchingMessage != null)
{
InsertIntoDB(matchingMessage);
}
}
else if (IsB(message))
{
lock (dictionaryLock)
{
if (receivedA.TryGetValue(message.id, out matchingMessage))
{
receivedA.Remove(message.id);
}
else
{
receivedB.Add(message.id, message);
}
}
if (matchingMessage != null)
{
InsertIntoDB(message);
}
}
else
{
// not A or B, do whatever
}
}
に役立ちます。トランザクションであれば、メモリ内の一致するAsとBsをトラッキングするだけで何かクラッシュやタイムアウトが発生した場合にトランザクションをキューに戻すことができます。 – Bruce