sp_getapplock (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例

对应用程序资源设置锁。

Transact-SQL 语法约定

语法

  
sp_getapplock [ @Resource = ] 'resource_name' ,  
     [ @LockMode = ] 'lock_mode'   
     [ , [ @LockOwner = ] 'lock_owner' ]   
     [ , [ @LockTimeout = ] 'value' ]  
     [ , [ @DbPrincipal = ] 'database_principal' ]  
[ ; ]  

参数

[ @Resource= ] “resource_name
指定标识锁资源的名称的字符串。 应用程序必须确保该资源名称是唯一的。 指定名称在内部哈希为可存储在 SQL Server 锁管理器中的值。 resource_namenvarchar(255), 没有默认值。 如果资源字符串长于 nvarchar(255),则会将其截断为 nvarchar(255)。

resource_name 是二进制比较的,因此无论当前数据库的排序规则设置如何,都区分大小写。

注意

一旦获取应用程序锁之后,则只能检索纯文本中的前 32 个字符;对剩余的字符执行哈希运算。

[ @LockMode= ] “lock_mode
要为特定资源获取的锁模式。 lock_mode为 varchar(32),没有默认值。 该值可以是以下任一值: 共享更新IntentSharedIntentExclusive独占。 有关详细信息,请参阅 锁定模式

[ @LockOwner= ] “lock_owner
锁的所有者,它是请求锁时所指定的 lock_owner 值 lock_owner是 varchar(32)。 该值可以是 Transaction(默认值)或 Session如果lock_owner值为 Transaction,默认情况下或显式指定,则必须从事务内执行sp_getapplock。

[ @LockTimeout= ] 'value'
锁超时值(毫秒)。 默认值与@@LOCK_TIMEOUT返回的值相同。 值为 -1(默认值)时表示没有超时期限(即无限期等待)。 若要指示锁请求应返回返回 -1 的返回代码,而不是在无法立即授予请求时等待锁,请指定 0。

[ @DbPrincipal= ] “database_principal
对数据库中的对象具有权限的用户、角色或应用程序角色。 函数的调用方必须是database_principal、dbo 或db_owner固定数据库角色的成员才能成功调用函数。 默认值为 public。

返回代码值

>= 0 (成功),或 < 0 (失败)

结果
0 锁已同时成功授予。
1 在等待释放其他不兼容锁后成功授予锁。
-1 锁请求超时。
-2 锁请求被取消。
-3 选择锁请求作为死锁牺牲品。
-999 指示参数验证或其他调用错误。

备注

对资源设置的锁与当前事务或当前会话相关联。 当事务提交或回滚时,将释放与当前事务相关联的锁。 注销会话时会释放与会话关联的锁。服务器出于任何原因关闭时,将释放所有锁。

sp_getapplock 创建的锁资源在会话的当前数据库中创建。 每个锁资源都由下列值的组合值进行标识:

  • 包含锁资源的数据库的数据库 ID。

  • 参数中指定的 @DbPrincipal 数据库主体。

  • @Resource 参数中指定的锁名。

只有 @DbPrincipal 参数中指定的数据库主体成员才能获取指定该主体的应用程序锁。 dbo 和 db_owner 角色成员被隐式视为所有角色成员。

可以使用 sp_releaseapplock 显式释放锁。 如果某个应用程序为同一锁资源多次调用 sp_getapplock,则必须调用 sp_releaseapplock 同样次数才能释放锁。 当锁所有者 Transaction 打开锁时,在提交或回滚事务时释放该锁。

如果为同一锁资源多次调用 sp_getapplock,但是在所有请求中指定的锁模式与现有模式不同,则对资源的影响将是两个锁模式的联合。 多数情况下,这意味着将锁模式提升为现有模式或新请求模式中更强的模式。 在锁定最终释放之前,将保留此更强大的锁模式。 例如,在以下调用顺序中,将以 Exclusive 模式而非 Shared 模式控制资源。

USE AdventureWorks2022;  
GO  
BEGIN TRANSACTION;  
DECLARE @result int;  
EXEC @result = sp_getapplock @Resource = 'Form1',   
               @LockMode = 'Shared';  
EXEC @result = sp_getapplock @Resource = 'Form1',   
               @LockMode = 'Exclusive';  
EXEC @result = sp_releaseapplock @Resource = 'Form1';  
COMMIT TRANSACTION;  
GO  

如果应用程序锁发生死锁,则该死锁不会回滚请求此应用程序锁的事务。 必须手动完成任何可能需要作为返回值结果的回滚。 因此,建议在代码中使用错误检查,如果返回某些值(例如 -3),则启动 ROLLBACK TRANSACTION 或替代操作。

下面是一个示例:

USE AdventureWorks2022;  
GO  
BEGIN TRANSACTION;  
DECLARE @result int;  
EXEC @result = sp_getapplock @Resource = 'Form1',   
               @LockMode = 'Exclusive';  
IF @result = -3  
BEGIN  
    ROLLBACK TRANSACTION;  
END  
ELSE  
BEGIN  
    EXEC @result = sp_releaseapplock @Resource = 'Form1';  
    COMMIT TRANSACTION;  
END;  
GO  

SQL Server 使用当前数据库 ID 来限定资源。 因此,如果在不同数据库中执行 sp_getapplock,即便使用了相同的参数值,结果仍然是对单独资源使用单独锁。

使用sys.dm_tran_locks动态管理视图或sp_lock系统存储过程检查锁信息,或使用 SQL Server Profiler 监视锁。

权限

要求具有 public 角色的成员身份。

示例

下面的示例对 Form1 数据库中的资源 AdventureWorks2022 设置共享锁,使其与当前事务相关联。

USE AdventureWorks2022;  
GO  
BEGIN TRAN;  
DECLARE @result int;  
EXEC @result = sp_getapplock @Resource = 'Form1',   
               @LockMode = 'Shared';  
COMMIT TRAN;  
GO  

以下示例指定 dbo 作为主体数据库。

BEGIN TRAN;  
EXEC sp_getapplock @DbPrincipal = 'dbo', @Resource = 'AdventureWorks2022',   
     @LockMode = 'Shared';  
COMMIT TRAN;  
GO  

另请参阅

APPLOCK_MODE (Transact-SQL)
APPLOCK_TEST (Transact-SQL)
sp_releaseapplock (Transact-SQL)