2012-02-03 58 views
1

当我在sql server 2008中调用存储过程时,我遇到了死锁问题。一个xml字符串通过biztalk传入存储过程,可以多次调用迅速连续。我遇到的问题是,如果快速连续调用5次该过程,则前4个调用将回滚,并且由于死锁,最后一次调用会被提交到数据库。下面是该过程的代码 - 它使用OPENXML解析xml字符串并插入到表A中。然后,我从表A中获取新的唯一标识符,并将多个子记录插入到表B中。关于如何解决此问题的任何指导将非常感谢。在存储过程中执行多个插入时Sql Server死锁错误

错误消息: System.Data.SqlClient.SqlException(0x80131904):事务(进程ID XX)在锁资源上与另一个进程死锁并被选作死锁受害者。重新运行交易。

表详细
表A
- ID INT标识(1,1)主键,
- ColumnA VARCHAR(15)NOT NULL,
- ColumnB VARCHAR(20)NOT NULL,
- AddedDateTime日期时间默认(GETDATE())

表B
- ID INT标识(1,1)主键,
- TableAId INT不为空,(FK)
- ColumnC VARCHAR(30)不为空

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 
+0

你有更多的限制隔离级别尝试吗? – danihp 2012-02-03 20:53:12

+0

副手,它似乎是这个过程的长度与交易结合的副作用。这是否需要一个事务,即您的选择使用的数据必须由其他可能的并行操作未修改来创建插入? – 2012-02-03 20:54:41

回答

1

这种行为可能有很多不同的原因,所以你需要得到更多的事实。你需要知道隔离级别和他们为之奋斗的锁。这里就是我想要做的:

  1. 做好准备在管理工作室打电话给你的PROC
  2. 检查每个呼叫者他们所谓的PROC(DBCC USEROPTIONS)权前的Isolation Levels四个窗口。
  3. 确定四个呼叫者(@@ SPID)的SPID
  4. 从第五届开始您的测试之前,采取一切锁的快照:

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. 在表A插入后PROC中添加一个wait(WAITFOR DELAY '00:00:30'),这样你可以看看在运动中的事情。
  2. 开始运行在每个会话,但之后各PROC开始把锁的快照从你的第五窗口:

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 

分析结果并查看导致死锁情况的资源。您可能会遇到锁升级问题,即将行级锁升级为页或扩展级甚至表级锁。 Read here for a description of Lock Modes

最后一个观察:

你可能会用火由proc内开始交易,不指定SET XACT_ABORT ON(See here for details)被打。我怀疑这是否会导致您的当前行为,除非您的客户拥有令人惊讶的短暂超时时间,但我强烈建议添加。

+0

非常感谢你的sisdog,我会尝试这些步骤。 – gyochum 2012-02-06 23:02:06

相关问题