0

如果一个进程已经在另一个表上运行一个 select 语句,为什么在 RC 隔离级别运行事务的进程会持有IX页锁?我的意思是,我认为当语句完成时锁会被释放(这就是我们可以进行不可重复读取的原因)。

这是死锁xml:

<deadlock-list>
 <deadlock victim="process5cd048">
  <process-list>
   <process id="process5cd048" taskpriority="0" logused="10000" waittime="2220" schedulerid="3" kpid="5764" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2012-11-09T12:16:52.730" lastbatchcompleted="2012-11-09T12:16:52.730" lastattention="2012-11-08T17:33:28.597" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" loginname="cwcuser" isolationlevel="read committed (2)" xactid="1157173773" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000005b3f1719cc3b4ad87e96487fe7fbf624ab5c2984">
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))     </frame>
    </executionStack>
    <inputbuf>
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))    </inputbuf>
   </process>
   <process id="process33ebc8" taskpriority="0" logused="10676" waitresource="PAGE: 5:1:1144344" waittime="2221" ownerId="1157173773" transactionname="user_transaction" lasttranstarted="2012-11-09T12:16:52.197" XDES="0x41518b140" lockMode="S" schedulerid="5" kpid="5272" status="suspended" spid="62" sbid="0" ecid="9" priority="0" trancount="0" lastbatchstarted="2012-11-09T12:16:52.730" lastbatchcompleted="2012-11-09T12:16:52.730" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" isolationlevel="read committed (2)" xactid="1157173773" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" sqlhandle="0x020000005b3f1719cc3b4ad87e96487fe7fbf624ab5c2984">
SELECT * FROM WP_CashCenter_StockTransactionLine
                    WHERE [StockTransaction_id] IN (
                        SELECT DISTINCT [ST].[id]
                        FROM WP_CashCenter_StockTransaction AS [ST]
                            LEFT JOIN WP_CashCenter_StockTransactionLine AS [STL] ON ([STL].[StockTransaction_id] = [ST].[id])
                        WHERE [ST].[Type] IN (1, 0, 10, 9)
AND ([STL].[Direction] IN (1, 0) OR [STL].[id] IS NULL) 
AND [ST].[Status] IN (0, 1)
AND ([STL].[StockContainer_id] = 3000080311 OR [ST].[StockContainerID] = 3000080311))     </frame>
    </executionStack>
    <inputbuf>
    </inputbuf>
   </process>
   <process id="process4e13048" taskpriority="0" logused="11448" waitresource="PAGE: 5:1:1144209" waittime="2172" ownerId="1157175935" transactionname="user_transaction" lasttranstarted="2012-11-09T12:16:52.997" XDES="0x3458e63b0" lockMode="S" schedulerid="7" kpid="3912" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2012-11-09T12:16:53.070" lastbatchcompleted="2012-11-09T12:16:53.067" clientapp=".Net SqlClient Data Provider" hostname="CWCEINAW" hostpid="4908" loginname="cwcuser" isolationlevel="read committed (2)" xactid="1157175935" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="160" sqlhandle="0x02000000193c8a3bb37a516f7a7155b01a67b7772459f53e">
SELECT [D].*
                        FROM WP_Discrepancy as [D]
                        WHERE [D].[Level] = @Level
                        AND [D].[Status] IN (@StatusInProgress, @StatusConfirmed)
                        AND [D].[StockContainerID] = @StockContainerID     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@Level int,@StatusInProgress int,@StatusConfirmed int,@StockContainerID bigint)SELECT [D].*
                        FROM WP_Discrepancy as [D]
                        WHERE [D].[Level] = @Level
                        AND [D].[Status] IN (@StatusInProgress, @StatusConfirmed)
                        AND [D].[StockContainerID] = @StockContainerID    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <exchangeEvent id="Pipe43a6da400" WaitType="e_waitPipeGetRow" nodeId="1">
    <owner-list>
     <owner id="process33ebc8"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5cd048"/>
    </waiter-list>
   </exchangeEvent>
   <pagelock fileid="1" pageid="1144344" dbid="5" objectname="WebPortal.dbo.WP_CashCenter_StockTransactionLine" id="lock326ee4180" mode="IX" associatedObjectId="72057594149601280">
    <owner-list>
     <owner id="process4e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process33ebc8" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
   <pagelock fileid="1" pageid="1144209" dbid="5" objectname="WebPortal.dbo.WP_Discrepancy" id="lock339da6b80" mode="SIX" associatedObjectId="72057594163625984">
    <owner-list>
     <owner id="process5cd048" mode="SIX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process4e13048" mode="S" requestType="wait"/>
    </waiter-list>
   </pagelock>
  </resource-list>
 </deadlock>
</deadlock-list>

如您所见,进程process4e13048在 table 的某个页面上持有IXWP_CashCenter_StockTransactionLine。当前尝试执行的语句是一个SELECT无法完成的语句,因为它想要一个与进程process5cd048持有的SIXWP_Discrepancy锁相冲突的页面上的共享锁(这很明显)。

同样,为什么后一个进程会持有那个锁?根据执行堆栈,正在执行的语句是一个SELECTWP_CashCenter_StockTransactionLine

如果我正在使用Serializable IL运行事务,我希望在同一进程中由先前语句获取的锁能够保留。但事实并非如此。

谁能解释一下我在 RC 隔离级别上做错了什么。谢谢。

4

1 回答 1

1

我认为当语句完成时锁会被释放

不写锁(X、IX、S-IX 等)。写锁必须服从两阶段锁定,以便在事务结束时释放它们。想想相反的意思是什么:DELETE 在事务结束之前释放行删除的 X 锁,稍后并发事务用相同的键插入一个新行(它可以,因为没有锁),现在第一个事务想要回滚。它可以做什么,它不能插入它删除的行,因为键是同时被第二个事务获取的,所以它不能回滚。

因此,在运行 SELECT 时可能会发生死锁,因为运行这些选择的事务在运行 SELECT之前已经获得了写锁。

于 2012-11-09T15:25:48.297 回答