为什么以下SQL Server在事务中运行时会插入死锁?

时间:2009-06-15 05:10:09

标签: c# sql-server linq-to-sql deadlock transactionscope

我正在将记录插入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生成的)。出于某种原因,当我使用具有Seri​​alizable隔离级别的TransactionScope对象在事务中运行此代码时,SQL Server会引发死锁错误。我分析了死锁图事件,发现所涉及的两个进程都在等待另一个进行转换操作,因为我理解以下信息:

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

我的理解是,在第一个进程完成插入和选择标识之前,事务范围将阻止第二个进程执行插入。然而,情况似乎并非如此。任何人都可以通过线程安全的方式阐明实现我需要的最佳方法吗?

- 的更新 -

注意;我99%确定两个进程之间没有共享连接,因为每个进程都创建一个新的DataContext来与数据库通信。

- 再次更新 -

Remus Rusanu指出,一些遗漏的信息与问题有关,我试图根据死锁图报告简化场景,但我在这里扩展了解释。在我执行插入之前,我在相关表上执行存在查询以确定标记是否已存在。如果是的话我结束了交易。如果不是,则插入应该继续,然后我在具有Some_Int作为主键的表上执行此处未示出的更新,尽管更新纯粹是针对最后修改的值。 Tag表具有由auto inc ID和Some_Int组成的聚簇索引也很重要。我不认为这最后一条信息具有相关性,因为我尝试将表更改为仅将auto inc字段作为主键/聚簇索引无效。

感谢。

3 个答案:

答案 0 :(得分:7)

有问题的'转换'是'lock convert' from RangeS-S to RangeI-N,与“CONVERT”函数无关。您已将RangeS-S锁定放在PK_Tag_1索引上这一事实表明您正在做的不仅仅是INSERT。在尝试插入之前,您的交易是否有任何机会首先检查新记录是否“存在”?

答案 1 :(得分:0)

检查查询中使用的isolationLevel。请注意,TransactionScope默认使用 Serializable 隔离级别(http://msdn.microsoft.com/en-us/library/ms172152.aspx)。尝试将事务的隔离级别更改为Read Commited。

答案 2 :(得分:-1)

您根本不需要交易。 scope_identity()函数将返回最后在同一范围内创建的id,因此如果在获取id之前执行了另一个插入,则没有问题,因为它位于不同的范围内。