UPDATE锁如何防止常见形式的死锁?

Ian*_*oyd 6 sql-server sql-server-2008-r2

SQL服务器联机丛书说,UPDATE锁可以防止死锁的一种常见形式:

更新锁

更新(U)锁可防止常见形式的死锁.

它们如何防止常见的死锁形式?

那是什么意思?

一种常见的死锁形式是当两个进程尝试从共享(S)锁(即读锁)升级到Exclusive(X)锁时:

Process A                       Process B
========================        ========================
Acquire Shared lock
                                Acquire Shared lock
Attempt to escalate to X
Escalation waits on B 
                                Attempt to escalate to X
                                Escalation waits on A
Run Code Online (Sandbox Code Playgroud)

死锁.两个进程都在等待.

这一点在BOL中都有解释:

典型的更新模式包括读取记录的事务,获取资源(页面或行)上的共享(S)锁,然后修改行,这需要锁转换为独占(X)锁.如果两个事务获取资源上的共享模式锁,然后尝试同时更新数据,则一个事务会尝试将锁转换为独占(X)锁.共享模式到独占锁定转换必须等待,因为一个事务的独占锁定与另一个事务的共享模式锁定不兼容; 锁定等待发生.第二个事务尝试获取其更新的独占(X)锁.因为两个事务都转换为独占(X)锁,并且它们都在等待另一个事务释放其共享模式锁,所以会发生死锁.

使用更新锁来防止死锁

联机丛书没有解释更新(U)锁如何防止这种常见形式的死锁,他们所说的只是:

为避免此潜在的死锁问题,使用更新(U)锁.一次只有一个事务可以获得对资源的更新(U)锁定.如果事务修改资源,则更新(U)锁将转换为独占(X)锁.否则,锁将转换为共享模式锁.

描述不完整.如果您查看短语"一次只能有一个事务可以获取对资源的更新(U)锁定".这与独占(X)锁没有什么不同 - 只有一个事务可以在一次获得对资源的独占(X)锁.但是让我们试着弄清楚:

首先我们假设是一个正常的更新过程:

  • 获取共享(S)锁
  • 尝试升级到更新(U)锁定
  • 执行更新
  • 需要更改值,升级到独占(X)锁定
  • 升级到独家(X)锁定
  • 执行更新
  • 释放所有锁

所以现在添加第二个过程

Process A                       Process B
========================        ========================
Acquire Shared lock
                                Acquire Shared lock
Attempt to escalate to U
Escalation waits on B 
                                Attempt to escalate to U
                                Escalation waits on A
Run Code Online (Sandbox Code Playgroud)

死锁.两个进程都在等待.

更新(U)锁如何防止常见形式的死锁?

usr*_*usr 6

描述不完整.如果您查看短语"一次只能有一个事务可以获取对资源的更新(U)锁定".这与独占(X)锁没有什么不同 - 只有一个事务可以在一次获得对资源的独占(X)锁.

U锁与S锁兼容,而X锁不是这种情况.这意味着虽然确定要写入的行(使用U锁),但仍允许其他读取器.

所以现在添加第二个流程......

这里的误解是,作家从S升级到U.事实并非如此.他们从一开始就使用U. 它们稍后从U升级到X,但在这种情况下对于死锁没有任何意义.

为了更清楚:假设我们运行以下语句:

UPDATE T SET SomeCol = 1 WHERE (ID BETWEEN 1 AND 2) AND (SomeOtherCond = 1)
Run Code Online (Sandbox Code Playgroud)

假设这是在聚集索引上使用范围扫描执行的ID,并且SomeOtherCond = 1仅对该行执行ID = 2.这将让你的U锁两行,并升级到X与行ID = 2.行的U形锁ID = 2将提前释放.