游标锁定

在 SQL Server 中,游标定义中的 SELECT 语句遵守适用于任何其他 SELECT 语句的相同的事务锁定规则。但在游标中,可以根据指定的游标并发级别获取一套额外的滚动锁。

通过任何 SELECT 语句(包括游标定义中的 SELECT 语句)获取的事务锁由下列各项进行控制:

  • 连接的事务隔离级别设置。

  • FROM 子句中指定的任何锁定提示。

对于游标和独立的 SELECT 语句,这些锁都会保持到当前事务结束。SQL Server 在自动提交模式下运行时,每个 SQL 语句都是一个事务,并在语句结束时释放锁。如果 SQL Server 以显式或隐式事务模式运行,则这些锁将保持到事务提交或回滚。

例如,下面的两个 Transact-SQL 示例中所做的锁定实质上是相同的:

/* Example 1 */
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
BEGIN TRANSACTION
GO
SELECT * FROM AdventureWorks2008R2.Sales.Store;
GO

/* Example 2 */
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
GO
BEGIN TRANSACTION
GO
DECLARE abc CURSOR STATIC FOR
SELECT * FROM AdventureWorks2008R2.Sales.Store;
GO
OPEN abc
GO

将事务隔离级别设置为可重复读意味着:示例 1 中的独立 SELECT 语句和示例 2 中的 DECLARE CURSOR 包含的 SELECT 语句在所读取的每一行上都生成共享锁,并且这些共享锁一直保持到事务提交或回滚。

获取锁

尽管游标和独立的 SELECT 语句在获取的事务锁类型方面遵守相同的规则,但它们获取锁的时间不同。独立的 SELECT 语句或游标生成的锁总是在检索行时获取的。对于独立的 SELECT 语句,执行语句时会检索所有行。但游标会根据游标的类型在不同时间检索行:

  • 静态游标在打开游标时检索整个结果集。这将在打开时锁定结果集中的每一行。

  • 由键集驱动的游标在打开游标时检索结果集中每行的键。这将在打开时锁定结果集中的每一行。

  • 动态游标(包括通常的只进游标)只有在提取行时才进行检索。仅当行已提取时才能获取锁。

  • 快速只进游标在获取锁的时间上会有所不同,这取决于查询优化器选择的执行计划。如果选择动态计划,则在提取行之前不会得到任何锁。生成工作表后,行将被读入工作表并在打开时锁定。

游标也支持自己的并发规定,其中某些会在每次提取时生成额外的锁。这些滚动锁会保持到下次提取操作或游标关闭,以其中较早的为准。如果将提交时保持打开游标的连接选项设置为有效,则这些锁在提交和回滚操作过程中将一直保持。

请参阅

概念