SQL Server在读取未提交的隔离级别上发生了死锁。

huangapple go评论59阅读模式
英文:

SQL Server deadlock on read uncommitted isolation level

问题

我收到错误消息"事务(进程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)

英文:

I get error message "Transaction (Process ID 60) was deadlocked on lock resources with another process ...". I have two simple queries like:

Query 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     

Query 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  

I set the transaction isolation level to read uncommitted for both, I run the first query, and immediately run the second one, but I still get the deadlock error. As I know, there should be no lock with read uncommitted isolation level. So, what is the reason of deadlock?
(I use SQL Server 2014)

答案1

得分: 2

"READ UNCOMMITTED"适用于读取而不写入(INSERT、UPDATE、DELETE、TRUNCATE、MERGE...)。

Thom所说的非常正确。NOLOCK并不意味着不会放置锁。

甚至在某些情况下,即使在读取时,也会忽略NOLOCK,比如在使用ENCRYPT或DECRYPT函数时。

另外,READ UNCOMMITTED可能会在结果集中给出错误的行。阅读我写的论文(但它是用法语写的)。

英文:

As the name says "READ UNCOMMITTED" apply to READ no writes (INSERT, UPDATE, DELETE, TRUNCATE, MERGE...).

What Thom says is very true. NOLOCK does not mean that a lock will not be put.

And even in READs, under certain circumstances, NOLOCK is ignored, like when there is ENCRYPT or DECRYPT functions used.

And by the ways, READ UNCOMMITTED can give you false positive rows in the results set. Read the paper I wrote (but it is in french)...

huangapple
  • 本文由 发表于 2023年6月1日 17:00:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76380261.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定