、UPDLOCKを持つテーブルにストアドプロシージャを実行するときにデッドロックの回避。私は、ユーザーがWebページを訪問するたびに実行されるストアドプロシージャを維持していますHOLDLOCK
-- Existing tables
CREATE TABLE SourceAccount
(
Id bigint NOT NULL,
Value varchar(50) NOT NULL,
UpdateTime datetime2 NULL
)
CREATE TABLE TargetAccount
(
Id bigint NOT NULL,
Value varchar(50) NOT NULL,
UpdateTime datetime2 NULL
)
CREATE TABLE UpdatedCustomers
(
CustomerID bigint NOT NULL,
SyncTime datetime2 NOT NULL
)
ストアドプロシージャ:
CREATE PROCEDURE TriggerAccountSync (
@CustId bigint,
@LastUpdate DATETIME2)
AS
BEGIN
--if customer is outdated
IF EXISTS(SELECT 1 FROM UpdatedCustomers
WHERE CustomerID = @CustId AND SyncTime < @LastUpdate)
BEGIN
BEGIN TRY
INSERT INTO TargetAccount(Id, Value)
SELECT Id, Value
FROM SourceAccount
LEFT OUTER JOIN TargetAccount WITH (UPDLOCK, HOLDLOCK) ON TargetAccount.Id = SourceAccount.Id
WHERE SourceAccount.UpdateTime IS NULL
DELETE FROM TargetAccount
FROM SourceAccount
INNER JOIN TargetAccount WITH (UPDLOCK) ON TargetAccount.Id = SourceAccount.Id
WHERE TargetAccount.UpdateTime < @TimeStamp
UPDATE UpdatedCustomers
SET SyncTime = @LastUpdate
WHERE CustomerID = @CustId
END TRY
BEGIN CATCH
--there are multiple simultaneous calls, it can fail with deadlock
--don't raise error
END CATCH
END
END
私はTRY CATCH THROW END CATCH
を使用して例外をスローし、まだTargetAccount
テーブル上のデッドロックを回避することはできますか?私はそれが同期に失敗したときを知る必要があります。
ストアドプロシージャが完了しなかった場合は、テーブルのロックを解除する方法はありますか?
なぜ 'HOLDLOCK'?私の理解から、それはそのテーブルのセマンティクスを事実上 'SERIALIZABLE'分離レベルに変更します。並行性が低下するため、これらの分離セマンティクスが必要です。 –
@BenThul:TargetAccountテーブルは、同時に(複数のWebページから)、または様々な顧客が同時に同じ顧客によって更新することができます。したがって、そのテーブルへのダーティ・リード/ライトを確実にしたいと考えています。 –
SQLでは、デフォルトではダーティ・リードを取得しません。 「汚れた書き込み」については、同じ行を同時に更新する複数の人がいると仮定します。そのためには、クエリヒントを使用するのではなく、明示的なトランザクションですべてを処理していたと思います。しかし、私はあなたではありません。 –