我正在尝试使用SQL Server Profiler确定死锁的原因。
这是死锁图:
这两个陈述都是插入,后跟select scope_identity();
实际上有2个并发进程在循环中重复执行 insert-select_identity 。
我期望 insert 对聚集索引进行独占锁定,而 select 采用非共享锁定 - 聚集索引,然后他们等待彼此释放各自的权力。
我看到的是两个进程都在等待释放相同的资源 - 聚簇索引。怎么会这样?特定的追索权应属于一个过程或另一个过程。我在这里想念什么? 感谢所有提前。
编辑:是的,隔离级别是Serializible。
PS:可能,我对非聚集索引的共享锁的假设是错误的,只要我的select不包含where
语句
EDIT2: 这是xml的一部分:
<resource-list>
<keylock hobtid="72057594148028416" dbid="29" objectname="<confidential>" indexname="PK_WP_Inbound_StockTransactionLine" id="lock9641700" mode="RangeS-S" associatedObjectId="72057594148028416">
<owner-list>
<owner id="process8e09288" mode="RangeS-S"/>
</owner-list>
<waiter-list>
<waiter id="process991ce08" mode="RangeI-N" requestType="convert"/>
</waiter-list>
</keylock>
<keylock hobtid="72057594148028416" dbid="29" objectname="<confidential>" indexname="PK_WP_Inbound_StockTransactionLine" id="lock9641700" mode="RangeS-S" associatedObjectId="72057594148028416">
<owner-list>
<owner id="process991ce08" mode="RangeS-S"/>
</owner-list>
<waiter-list>
<waiter id="process8e09288" mode="RangeI-N" requestType="convert"/>
</waiter-list>
</keylock>
</resource-list>
根据这个,我认为它是由SERIALIZABLE隔离引起的范围扫描(谷歌搜索)。但是,我仍然不明白这是如何发生的以及建议的补救措施。
答案 0 :(得分:5)
考虑从访问相同记录的两个并行事务(T1和T2)调用以下代码。
Read LastRow
Insert AtLastRow
让我们说上下文切换发生在Read
。所以操作顺序是
T1 Read LastRow
T2 Read LastRow
T2 Insert AtLastRow // This will wait for T1 to finish.
T1 Insert AtLastRow // This will wait for T2 to finish. Hence deadlock!
以上阅读将Range S-S
锁定。最后插入还需要Range I-N
,这与其他事务持有的现有Range S-S
锁不兼容。因此它等待。
有多种方法可以解决这个问题。
如果您有任何问题,请与我们联系。