2

次のようなストアド プロシージャがあります。

USE [DBName]
GO
/****** Object:  StoredProcedure [dbo].[ProcName]    Script Date: 10/03/2012 12:10:16 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ProcName](@filter bigint, @n int)
AS
DELETE FROM TableName WITH (READPAST, UPDLOCK, ROWLOCK) OUTPUT(DELETED.ColumnName2)
WHERE TableName.ID in (select top (@n) ID from TableName where TableName.ColumnName1 = @filter)

このプロシージャは、ColumnName2 の最初の @n 値を返します (これらの値で表されるレコードはテーブルから削除されます)。私は vb メソッドからこのストアド プロシージャを使用していますが、通常はうまく機能します。ただし、私にはわからない理由で、例外がスローされることがあります。

You can only specify the READPAST lock in the READ COMMITTED or REPEATABLE READ isolation levels.

私の vb メソッドはこのストアド プロシージャを呼び出し、十分な値を取得できない場合は、新しい値を生成してこのストアド プロシージャを呼び出します。これは、十分な値が得られるまで繰り返されます。本質的に、TableName はキューのように機能し、vb メソッドはうまく機能しますが、上記の例外がスローされることがあります。何が原因で、私の問題の解決策は何ですか?

ストアド プロシージャを呼び出すコードのためだけに新しい接続を開始しようとしましたが、例外が再びスローされたため、役に立ちませんでした。次の記事を読んだにもかかわらず、何が解決策になるのかわかりません。

http://www.red-gate.com/messageboard/viewtopic.php?t=13614

ストアド プロシージャを呼び出すときの .NET READPAST ロック エラー

http://support.microsoft.com/kb/981995

http://blogs.technet.com/b/claudia_silva/archive/2011/08/08/replication-error-quot-you-can-only-specify-the-readpast-lock-in-the-read-committed-または-repeatable-read-isolation-levels-quot-generated-when-altering-published-table-columns.aspx

よろしくお願いします。

ラホス アルパド。

4

2 に答える 2

11

これで問題が解決するはずです

ALTER PROCEDURE [dbo].[ProcName](@filter bigint, @n int)
AS
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
DELETE FROM TableName WITH (READPAST, UPDLOCK, ROWLOCK) OUTPUT(DELETED.ColumnName2)
WHERE TableName.ID in (select top (@n) ID from TableName where TableName.ColumnName1 = @filter)

この設定が必要な READPAST を使用しているため、安全にスコープされている場合は、SP で明示的に設定することもできます。

ストアド プロシージャまたはトリガーで SET TRANSACTION ISOLATION LEVEL を発行した場合、オブジェクトが制御を返すと、分離レベルは、オブジェクトが呼び出されたときに有効だったレベルにリセットされます。

参考:SET TRANSACTION ISOLATION LEVEL

なぜそれが起こっているのかというと、考えられる理由は、接続プールと、SQL 呼び出し間の混合トランザクション分離レベルです。

于 2012-10-03T09:30:27.557 に答える
4

まず、DELETE が正しくありません。あなたが望むものを達成するには、次のように書く必要があります:

WITH T AS (
   SELECT TOP (@n)
    ColumnName2
   FROM TableName WITH (READPAST, UPDLOCK, ROWLOCK) 
   WHERE ColumnName1 = @filter)
DELETE FROM T
OUTPUT DELETED.ColumnName2;

この書き直しにより、UPDATE とトップ ID のスキャンの間の競合状態が解消されます。機能するためには、WHERE 句が SARGable である必要があります (つまり、ColumnName1 がインデックスである必要があります)。詳細については、テーブルをキューとして使用するを参照してください。

質問に戻ります。異なる分離レベルの原因は何ですか? さて、あなたがここに投稿しなかったコードの何かです。敢えて言うなら、それTransactionScopeはデフォルトのコンストラクターで構築されたオブジェクトでなければなりません。これがどのように発生し、なぜ悪いのかについては、有害と見なされる new TransactionScope() の使用を参照してください。リンクされた記事には解決策も含まれています。トランザクションスコープの明示的なコンストラクターを使用してTransactionOptions、目的の分離レベルを明示的に指定するものを受け入れます。

于 2012-10-03T10:32:43.793 に答える