ストアドプロシージャを介して複数の注文プロセッサからアクセスされる注文キューがあります。各プロセッサは一意のIDを渡します。このIDは、次の20件の注文を自分で使用するためにロックするために使用されます。次に、ストアドプロシージャは、これらのレコードを注文プロセッサに返し、処理を行います。
複数のプロセッサが同じ「OrderTable」レコードを取得できる場合で同時に処理しようとする場合があります。これにより、最終的にはプロセスの後半でエラーがスローされます。
私の次の行動方針は、各プロセッサが利用可能なすべての注文を取得し、プロセッサをラウンドロビンすることですが、コードスレッドのこのセクションを安全にし、プロセッサがいつでもレコードを取得できるようにしたいと考えていました。
明示的に-この競合状態が発生している理由と、問題を解決する方法についてのアイデア。
BEGIN TRAN
UPDATE OrderTable WITH ( ROWLOCK )
SET ProcessorID = @PROCID
WHERE OrderID IN ( SELECT TOP ( 20 )
OrderID
FROM OrderTable WITH ( ROWLOCK )
WHERE ProcessorID = 0)
COMMIT TRAN
SELECT OrderID, ProcessorID, etc...
FROM OrderTable
WHERE ProcessorID = @PROCID
編集:
私は自分の答えをチェックするためにグーグルで検索しました "SQL ServerでのREADPASTおよびUPDLOCKを使用したデータキューの処理" 。私がこのソリューションを読んで遊んだのは何年も前のことです。
元の:
READPASTヒントを使用する場合、ロックされた行はスキップされます。 ROWLOCKを使用したので、ロックのエスカレーションを回避する必要があります。私が知ったように、UPDLOCKも必要です。
したがって、プロセス1は20行をロックし、プロセス2は次の20行を取得し、プロセス3は行41から60を取得します。
更新は次のように書くこともできます:
UPDATE TOP (20)
foo
SET
ProcessorID = @PROCID
FROM
OrderTable foo WITH (ROWLOCK, READPAST, UPDLOCK)
WHERE
ProcessorID = 0
更新、2011年10月
これは、SELECTとUPDATEが一度に必要な場合に、OUTPUT句を使用してよりエレガントに行うことができます。
ServiceBrokerを使用できます。また、sp_getapplockを使用して、行へのアクセスをシリアル化することもできます。これにより、競合状態が解消されます。
「独自のロック(SQLのミューテックス)を作成して並行性を支援する」 http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx