1

SQL Server 2008 でストアド プロシージャを呼び出すと、デッドロックの問題が発生します。xml 文字列は、biztalk によってストアド プロシージャに渡され、立て続けに何度も呼び出すことができます。私が直面している問題は、プロシージャが立て続けに 5 回呼び出されると、最初の 4 回の呼び出しがロールバックされ、デッドロックのために最後の呼び出しがデータベースにコミットされることです。以下は手順のコードです。OPENXML を使用して xml 文字列を解析し、テーブル A に挿入します。次に、テーブル A から新しい一意の識別子を取得し、複数の子レコードをテーブル B に挿入します。この問題を解決する方法に関するガイダンスは、感謝します。

エラー メッセージ: System.Data.SqlClient.SqlException (0x80131904): トランザクション (プロセス ID XX) は別のプロセスのロック リソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します。

テーブルの詳細
TableA
- Id int identity(1,1) Primary Key,
- ColumnA varchar(15) not null,
- ColumnB varchar(20) not null,
- addedDateTime datetime default(getdate())

TableB
- Id int identity(1,1) Primary Key,
- TableAId int not null, (FK)
- ColumnC varchar(30) not null

XML

<Transactions>
<Transaction>
    <ColumnA>Column A Value</ColumnA>
    <ColumnB>Column B Value</ColumnB>
    <ChildItems>
        <ChildItem>
            <ColumnC>Column C Value</ColumnC>
        </ChildItem>
        <ChildItem>
            <ColumnC>Another Column C Value</ColumnC>
        </ChildItem>
        <ChildItem>
            <ColumnC>Yet Another Column C Value</ColumnC>
        </ChildItem>
    </ChildItems>



ストアド プロシージャ

 CREATE PROCEDURE [dbo].[proc_ProcessXml] 
    (
        @ResponseXml varchar(max)
    )
    WITH EXECUTE AS CALLER  
    AS

    BEGIN TRANSACTION
    DECLARE @xmlHandle int
    declare @tableAId int

    EXEC sp_xml_preparedocument @xmlHandle OUTPUT, @ResponseXml, 

    INSERT INTO TableA 
    (
        ColumnA,
        ColumnB             
   ) 
   SELECT columnA, columnB
    FROM OPENXML(@xmlHandle, '/Transactions/Transaction', 1)
    WITH(
        columnA varchar(15) 'ColumnA',      
        columnB varchar(20) 'ColumnB'
    )

    select @tableAId = SCOPE_IDENTITY()

    INSERT INTO TableB 
    (
        TableAId,
        ColumnC             
    )  
    SELECT @tableAId, columnC
    FROM OPENXML(@xmlHandle, '/Transactions/Transaction/ChildItems/ChildItem', 1) 
    WITH(       
        columnC varchar(30) 'ColumnC',
    )

    EXEC sp_xml_removedocument @xmlHandle

    IF @@ERROR <> 0
        BEGIN                   
            ROLLBACK
        END
    ELSE
        BEGIN           
            COMMIT
        END
4

1 に答える 1

1

この動作にはさまざまな原因が考えられるため、より多くの事実を取得する必要があります。分離レベルと、彼らが争っているロックを知る必要があります。これが私がすることです:

  1. Mgmt Studio で 4 つのウィンドウを準備して、proc を呼び出します
  2. proc (dbcc useroptions) を呼び出す直前に、各呼び出し元 の分離レベルを確認します。
  3. 4 つの発信者の spid を特定する (@@spid)
  4. 5 番目のセッションからテストを開始する前に、すべてのロックのスナップショットを作成します。

.

select
     object_name(P.object_id) as TableName, L.*
into
    #preTestLocks
from     
    sys.dm_tran_locks L
    join sys.partitions P on L.resource_associated_entity_id = p.hobt_id
where
     object_name(P.object_id) in ('TableA','TableB')
  1. TableA 挿入 (WAITFOR DELAY '00:00:30') の後に proc 内に待機を追加して、動いているものを見ることができるようにします。
  2. 各セッションで proc の実行を開始しますが、各開始後に 5 番目のウィンドウからロックのスナップショットを取得します。

.

select
     object_name(P.object_id) as TableName, L.*
into
    #lock1  --<<CHANGE AFTER EACH RUN (#lock2, #lock3 etc.)
from     
    sys.dm_tran_locks L
    join sys.partitions P on L.resource_associated_entity_id = p.hobt_id
where
    resource_session_id in (1,2,3,4) --<<YOUR SPID'S

結果を分析し、デッドロック状態の原因となっているリソースを確認します。行レベルのロックをページまたは拡張、さらにはテーブルレベルのロックにエスカレートしているロックエスカレーションの問題が発生している可能性があります。 ロックモードの説明については、こちらをお読みください

最後の観察:

SET XACT_ABORT ON を指定せずに proc 内でトランザクションを開始すると、火遊びをしている可能性があります (詳細については、こちらを参照してください)。クライアントのタイムアウトが驚くほど短い場合を除き、これが現在の動作を引き起こしているとは思えませんが、それを追加することを強くお勧めします.

于 2012-02-04T20:52:48.703 に答える