Las*_*sus 6 c# sql-server deadlock transactionscope linq-to-sql
我目前正在将记录插入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]
Run Code Online (Sandbox Code Playgroud)
(这是使用Linq-to-SQL生成的).出于某种原因,当我使用具有Serializable隔离级别的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>
Run Code Online (Sandbox Code Playgroud)
我的理解是,事务范围将阻止第二个进程执行插入,直到第一个进程完成插入和选择标识.然而,情况似乎并非如此.任何人都可以通过线程安全的方式阐明实现我需要的最佳方法吗?
- 更新 -
请注意; 我99%确定两个进程之间没有共享连接,因为每个进程都创建一个新的DataContext来与数据库通信.
- 再次更新 -
Remus Rusanu指出一些省略的信息与问题有关,我试图根据死锁图报告简化场景,但我在这里扩展了解释.在我执行插入之前,我在相关表上执行存在查询以确定标记是否已存在.如果是的话我结束了交易.如果不是插入应该继续,然后我在具有Some_Int主键的表上执行更新(此处未显示),尽管更新纯粹是针对最后修改的值.Tag表具有由auto inc ID和Some_Int组成的聚簇索引也很重要.我不认为这最后一条信息具有相关性,因为我尝试将表更改为仅将auto inc字段作为主键/聚簇索引无效.
谢谢.
有问题的'转换'是从RangeS-S到RangeI-N的'锁定转换',与任何方式的'CONVERT'功能无关.您已将RangeS-S锁定放在PK_Tag_1索引上这一事实表明您正在做的不仅仅是INSERT.在尝试插入之前,您的交易是否会先检查新记录是否"存在"?