键范围锁定

键范围锁定解决了幻像读并发问题,并支持可串行事务。键范围锁覆盖单个记录以及记录之间的范围,可以防止对事务访问的记录集进行幻像插入或删除。键范围锁仅用于代表在可串行隔离级别上操作的事务。

可串行性要求如果任意一个查询在一个事务中后面的某一时刻再次执行,其所获取的行集应与该查询在同一事务中以前执行时所获得的行集相同。如果本查询试图提取的行不存在,则在试图访问该行的事务完成之前,其它事务不能插入该行。如果允许另一个事务插入该行,则它将以幻像出现。

如果另一个事务试图插入驻留在锁定数据页上的行,页级锁定可以防止添加幻像行,并维护可串行性。但是,如果该行要添加到未被第一个事务锁定的数据页,应设定锁定机制防止添加该行。

键范围锁通过覆盖索引行和索引行之间的范围来工作(而不是锁定整个基础表的行)。因为第二个事务在该范围内进行任何行插入、更新或删除操作时均需要修改索引,而键范围锁覆盖了索引项,所以在第一个事务完成之前会阻塞第二个事务的进行。

键范围锁模式

键范围锁包括范围组件和行组件,按范围-行格式指定:

范围 模式
  • 描述
RangeS S RangeS_S 共享范围,共享资源锁;可串行范围扫描。
RangeS U RangeS_U 共享范围,更新资源锁;可串行更新扫描。
RangeI NULL RangeI_N 插入范围,空资源锁;用于在索引中插入新键之前测试范围。
RangeX X RangeX_X 排它范围,排它资源锁;用于更新范围中的键。

说明  内部空锁模式与所有其它锁模式相兼容。

键范围锁模式有一个兼容性矩阵,表示哪些锁与在重叠键和范围上获取的其它锁兼容。

  现有的授权模式
请求模式 S U X RangeS_S RangeS_U RangeI_N RangeX_X
共享 (S)
更新 (U)
排它 (X)
RangeS_S
RangeS_U
RangeI_N
RangeX_X

会话锁

当键范围锁与其它锁重叠时,创建会话锁。

锁 1 锁 2 会话锁
S RangeI_N RangeI_S
U RangeI_N RangeI_U
X RangeI_N RangeI_X
RangeI_N RangeS_S RangeX_S
RangeI_N RangeS_U RangeX_U

在不同的复杂环境下(有时是在运行并发进程时),可以在一小段时间内观察到会话锁。

可串行范围扫描、单独提取、删除和插入

键范围锁定确保以下四种方案是可串行的:

然而,在可以发生键范围锁定之前,必须满足下列条件:

下列每种方案的示例都基于下图中的表和索引。

范围扫描查询

为了确保范围扫描查询是可串行的,每次在同一事务中执行的相同查询应返回同样的结果。其它事务不能在范围扫描查询中插入新行;否则这些插入将成为幻像插入。例如,下面的查询使用前面插图中的表和索引:

SELECT name FROM mytable WHERE name BETWEEN 'A' AND 'C'

键范围锁放置在与数据行范围(名称在值 Adam 和 Dale 之间的行)对应的索引项上,以防止添加或删除满足上述查询条件的新行。虽然此范围中的第一个名称是 Adam,但是此索引项的 RangeS_S 模式键范围锁确保了以字母 A 开头的新名称(如 Abigail)不能添加在 Adam 之前。同样,Dale 索引项的 RangeS_S 键范围锁确保了以字母 C 开头的新名称(如 Clive)不能添加在 Carlos 之后。

说明  控制的 RangeS_S 锁数量为 n+1,此处 n 是满足查询条件的行数。

单独提取不存在数据

如果事务中的查询试图选择不存在的行,则以后在相同的事务中发出这一查询时,必须返回相同的结果。不允许其它事务插入不存在的行。例如,对于下面的查询:

SELECT name FROM mytable WHERE name = 'Bill'

键范围锁放置在对应于名称范围 Ben 到 Bing 之间的索引项上,因为名称 Bill 将插入到这两个相邻的索引项之间。RangeS_S 模式键范围锁放置在索引项 Bing 上。这样可以防止任何其它事务在索引项 Ben 和 Bing 之间插入插入值(如 Bill)。

删除操作

在事务中删除值时,在事务执行删除操作期间不必锁定值所属的范围。锁定删除的键值直至事务结束足以保持可串行性。例如,对于下面的 DELETE 语句:

DELETE mytable WHERE name = 'Bob'

排它 (X) 锁放置在对应于名称 Bob 的索引项上。其它事务可以在删除值 Bob 的前后插入或删除值。但是任何试图读取、插入或删除值 Bob 的事务将被阻塞,直到删除的事务提交或回滚为止。

可以使用下列三种基本锁模式执行范围删除:行锁、页锁或表锁。页、表或行锁定策略由查询优化器确定,或者可以由用户通过优化程序提示(如 ROWLOCK、PAGLOCK 或 TABLOCK)指定。在使用页锁或表锁的情况下,SQL Server 立即释放包含已删除行的索引页,并假定从页中删除了所有行。相反,使用行锁时,所有删除的行只是被标记为已删除;以后通过后台任务从索引页中删除它们。

插入操作

在事务中插入值时,在事务执行插入操作期间不必锁定值所属的范围。锁定插入的键值直至事务结束足以维护可串行性。例如,对于下面的 INSERT 语句:

INSERT mytable VALUES ('Dan')

RangeI_N 模式键范围锁放置在对应于名字 David 的索引项上以测试范围。如果已授权锁定,则插入 Dan,并且排它 (X) 锁放置在值 Dan 上。RangeI_N 模式键范围锁仅对测试范围必需,而不在执行插入操作的事务期间保留。其它事务可以在插入值 Dan 的前后插入或删除值。但是,任何试图读取、插入或删除值 Dan 的事务将被阻塞,直到插入的事务提交或回滚为止。