6

現在、SQL Server テーブルにレコードを挿入し、次のように自動インクリメント ID を選択しています。

(@p0 int,@p1 nvarchar(8))INSERT INTO [dbo].[Tag]([Some_Int], [Tag])
VALUES (@p0, @p1)

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value] 

(これは Linq-to-SQL を使用して生成されました)。Serializable 分離​​レベルで TransactionScope オブジェクトを使用してトランザクション内でこのコードを実行すると、何らかの理由で SQL Server がデッドロック エラーをスローします。デッドロック グラフ イベントを分析したところ、関連する 2 つのプロセスがそれぞれ、変換操作を実行するために相互に待機していることがわかりました。次の情報を理解しているためです。

<resource-list>
   <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176">
    <owner-list>
     <owner id="processc9be40" mode="RangeS-S"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc9ae38" mode="RangeI-N" requestType="convert"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176">
    <owner-list>
     <owner id="processc9ae38" mode="RangeS-S"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc9be40" mode="RangeI-N" requestType="convert"/>
    </waiter-list>
   </keylock>
  </resource-list>

私の理解では、トランザクション スコープは、最初のプロセスが ID の挿入と選択の両方を完了するまで、2 番目のプロセスが挿入を実行できないようにするというものでした。しかし、そうではないようです。スレッドセーフな方法で私が必要とするものを達成するための最良のアプローチに誰かが光を当てることができますか?

--更新--

注意してください。それぞれがデータベースと通信するための新しい DataContext を作成するため、2 つのプロセス間で接続が共有されていないことは 99% 確信しています。

--再度更新--

Remus Rusanu は、いくつかの省略された情報が問題に関連していることを指摘しました。デッドロック グラフ レポートに基づいてシナリオを単純化しようとしましたが、ここで説明を拡張しました。挿入を行う前に、問題のテーブルに対して既存のクエリを実行して、タグが既に存在するかどうかを確認します。もしそうなら、私は取引を終了します。Some_Intそうでない場合は、挿入を続行する必要があります。次に、更新は純粋に最後に変更された値に対するものですが、ここには示されていませんが、主キーを持つテーブルで更新を実行します。Tag テーブルに、auto inc ID と Some_Int の両方で構成されるクラスター化インデックスがあることも重要な場合があります。この最後の情報は関連性があるとは思いませんでした。主キー/クラスター化インデックスとして auto inc フィールドのみを持つようにテーブルを変更しようとしても役に立たなかったからです。

ありがとう。

4

3 に答える 3

7

問題の「変換」は RangeS-S から RangeI-N への「ロック変換」であり、「CONVERT」機能とはまったく関係ありません。RangeS-S ロックが既に PK_Tag_1 インデックスに配置されているという事実は、INSERT 以外のことを行っていることを示しています。万が一、あなたのトランザクションは、挿入を試みる前に、新しいレコードが「存在する」かどうかを最初にチェックしますか?

于 2009-06-15T11:50:59.590 に答える
0

クエリで使用されているisolationLevelを確認してください。TransactionScopeは 、デフォルトでシリアル化可能な分離レベル( http://msdn.microsoft.com/en-us/library/ms172152.aspx)を使用することに注意してください。トランザクションの分離レベルをReadCommitedに変更してみてください。

于 2010-01-31T16:22:50.730 に答える