SQL Server 在读取未提交隔离级别上死锁

SQL Server deadlock on read uncommitted isolation level

提问人:Mohammad Galouz Lee 提问时间:6/1/2023 更新时间:6/2/2023 访问量:170

问:

我收到错误消息“事务(进程 ID 60)在另一个进程的锁定资源上死锁...”。我有两个简单的查询,例如:

查询 1:

BEGIN try    
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN tran  
 
    update RestaurantAccount set CreatedOn = GETDATE()
        where Id = 1
    
    WAITFOR DELAY '00:00:6'
    
    update RestaurantInvoice set CreatedOn = GETDATE()
        where Id = 1
 
commit tran    

END try    
BEGIN catch    

IF(@@TRANCOUNT > 0)    
rollback tran    
 
          SELECT  
             cast(1 as bit) as hasError
            ,ERROR_LINE() AS ErrorLine  
            ,(isnull(ERROR_MESSAGE(),'') + isnull(ERROR_PROCEDURE(),'')) AS ErrorMessage
END catch     

查询 2:

BEGIN try    
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN tran  
 
    update RestaurantInvoice set CreatedOn = GETDATE()
        where Id = 1
    
    WAITFOR DELAY '00:00:6'
    
    update RestaurantAccount set CreatedOn = GETDATE()
        where Id = 1

commit tran    

END try    
BEGIN catch    

IF(@@TRANCOUNT > 0)    
rollback tran    

         SELECT  
             cast(1 as bit) as hasError
            ,ERROR_LINE() AS ErrorLine  
            ,(isnull(ERROR_MESSAGE(),'')  ) AS ErrorMessage

END catch  

我将两者的事务隔离级别设置为读取未提交,我运行第一个查询,并立即运行第二个查询,但我仍然收到死锁错误。据我所知,不应该有具有读取未提交隔离级别的锁。那么,死锁的原因是什么呢? (我使用SQL Server 2014)

sql-server 数据库死锁 sqltransaction

评论

0赞 Dale K 6/1/2023
检查死锁图,查看哪些资源导致了问题。
4赞 Thom A 6/1/2023
“据我所知,不应该有具有读取未提交隔离级别的锁。”事实并非如此。您尝试在两个语句中执行相同的行,读取未提交对此无济于事。第二批将无法,因为第一批已锁定行,而第一批则不能,因为第二批已锁定行。这种行为是完全可以预期的,因为任何一种说法都不能继续下去,直到另一种说法继续下去,因此陷入僵局。UPDATEUPDATEUPDATERestaurantAccountUPDATERestaurantInvoice
2赞 Thom A 6/1/2023
当它尝试访问被另一个事务锁定的行时,您期望做什么?只是做什么..?READ UNCOMMITTEDUPDATEUPDATE
3赞 Martin Smith 6/1/2023
读取未提交仅“帮助”读取器/写入器死锁。不是写入器/写入器死锁。如今,快照隔离是避免读取器/写入器死锁的首选方法
1赞 Thom A 6/1/2023
相关阅读:更新语句,设置事务隔离级别读取未提交

答:

2赞 SQLpro 6/1/2023 #1

顾名思义,“READ UNCOMMITTED”适用于不写(INSERT、UPDATE、DELETE、TRUNCATE、MERGE...)。

汤姆说的非常正确。NOLOCK并不意味着不会上锁。

即使在 READ 中,在某些情况下,NOLOCK 也会被忽略,例如当使用 ENCRYPT 或 DECRYPT 函数时。

顺便说一句,READ UNCOMMITTED 可能会在结果集中为您提供误报行。阅读我写的论文(但它是法语的)......