首页 > 解决方案 > 存储过程的应用程序锁

问题描述

我有一个安排工作的应用程序。我对作业的控制有限。该作业执行存储过程。有什么办法可以锁定存储过程,使作业不能同时执行这个存储过程?我想检查是否有 SQL 服务器提供的东西。

标签: sqlsql-server

解决方案


您可以使用sp_getapplock来获取“自定义”或“应用程序”锁,并使用 sp_releaseapplock来释放它。

辅助函数是:

  • APPLOCK_TEST - 返回有关是否可以在特定应用程序资源上授予锁定的信息
  • APPLOCK_MODE - 此函数返回锁定所有者在特定应用程序资源上持有的锁定模式

请注意,sp_getapplock不会锁定数据库中的任何表,它只会创建一个自定义命名锁。应用程序可以使用此功能来处理并发。

例子:

在 SSMS 中打开 2 个查询窗口,并在 1 分钟内运行以下代码。

DECLARE
        @LockResult         INT
    ,   @LockErrorMessage   NVARCHAR(MAX) = N'Failed to acquire lock.'
;

EXEC @LockResult = sys.sp_getapplock
        @Resource       = N'TestResource'
    ,   @LockMode       = N'Exclusive'
    ,   @LockOwner      = N'Session'
    ,   @LockTimeout    = 60000           /* 1 minute */
    ,   @DbPrincipal    = N'public'
;

IF (@LockResult < 0) BEGIN
    THROW 50000, @LockErrorMessage, 0;
END
ELSE
BEGIN
    SELECT 1 AS test;

    /* EXEC MyControlledSP */
    /* For demonstration purposes only! */
    WAITFOR DELAY '00:02:00';

    /* The work is done, release the lock */
    EXEC sys.sp_releaseapplock
            @Resource       = N'TestResource'
        ,   @LockOwner      = N'Session'
        ,   @DbPrincipal    = N'public'
    ;
END;

您可以在 SP 本身中获取锁并仅在成功获取锁时运行它的主体,因此使用该存储过程的任何应用程序/进程也将隐式检查锁,您不会依赖于调整所有应用程序/处理。

不要忘记释放锁,尤其是当所有者是会话时。关闭连接(例如关闭查询窗口)将自动释放锁。


如果计划任务是 SQL Server 代理作业,则不必进行自定义锁定,因为一个作业只能运行一次,并且当有一个正在运行的实例时,代理不会启动第二个(即使调度会这样说的)。


推荐阅读