SQL Server データベース テーブルをワーク キューとして使用しています。
1 人のライターと複数のリーダーがいます。
ライターは、キュー テーブルの新しいレコードを作成します (INSERT)。
各リーダーは、使用する特定のステータス (SELECT) のレコードを探し、レコードの 1 つのバッチを取得し、各レコードを所有済みとしてマークし (UPDATE)、それらを処理してから、処理されたすべてのレコードを完了または失敗としてマークします (UPDATE)。レコードのワークフローは単純です。ステータスは、追加の「A」から処理中の「B」、完了の「C」または失敗の「F」のいずれかに変化します。そして、各レコードの所有者は、ステータスが「A」のときの未設定から、残りのステップのリーダーを識別する一意の識別子になります。一意の識別子 (Decimal)、ステータス (nchar(1))、ライターのより大きなバッチを識別する追加のバッチ ID (int) が、処理における 3 つの重要なフィールドです。また、テーブルには、LINQ が同時実行チェックに使用するタイムスタンプ フィールドがあります。
2 人のリーダーが処理する同じレコードを選択することによるロックの遅延と更新の失敗を防ぐ必要があります。処理作業の一環として、完了までに不確定な時間がかかる Web サービス呼び出しが行われます。私たちは Web サービス ベンダーにトランザクションで支払うので、呼び出しを行いたくないので、同じレコードを処理する別のプロセスを見つけます。このようなエラーは、数千ドルの費用がかかります。
私はこの記事を読みました:
READPAST および UPDLOCK を使用した SQL Server でのデータ キューの処理
それは有望に見えましたが、LINQ to SQL を使用することにしました。私はこの記事を読みました:
後者は、SQL プロシージャを大まかにラップする以外に、UPDLOCK を使用するように LINQ に指示する方法はないと述べています。これは、LINQ が楽観的同時実行を使用し、これらの機能が悲観的ロックを想定しているためです。
では、LINQ がサポートする機能を使用してこの問題を解決するにはどうすればよいでしょうか? 私のアプリケーションはマルチスレッドですが、同じキュー テーブルに対して複数のインスタンスを実行できます。そのため、1 つのディスパッチャだけで各コンシューマ スレッドにレコードを渡すことはできません。
.NET 4.0 を使用しています。私のアプリケーションは、単純な古い Windows コンソール アプリケーションです。このソリューションは、SQL Server 2005 および SQL Server 2008 R2 で動作するはずです。メッセージング システムを使用する必要はありません。
更新:SOに関するさらなる研究。この記事を見つけました:
答えは、私が除外したディスパッチャ スレッドを持つことを推奨しています。
更新 2:SO に関する別の記事が見つかりました:
これは本当に有望に見えます。ダイレクト SQL を実行する必要がありますが、レコードにマークを付けて ID を取得したら、残りは L2S で行うことができます。