如何在不取消新呼叫的情况下锁定存储过程

时间:2016-03-14 12:34:57

标签: sql-server sql-server-2012

我有一个每分钟从作业调用的存储过程,但也可以在作业外的任何时间调用它。

如果我在调用该作业的同时调用存储过程,则会出现问题。

我需要的是让第二个呼叫等到第一个完成然后第二个呼叫开始。

我按照Link使用了sp_getapplock。

注意:我尝试了sp_getapplock但它取消了第二次调用。

更新:   这是我使用

的样本
ALTER PROCEDURE TestingLocking
AS  
BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

    DECLARE @returnCode INT, @DriverID INT, @OrderID int, @CarTypeID int

    EXEC @returnCode = sp_getapplock
            @Resource = 'TestingLocking',
            @LockMode = 'Exclusive',
            @LockOwner = 'Session',
            @LockTimeout = 5,
            @DbPrincipal  = 'public'

    DECLARE db_cursor CURSOR FOR 
        SELECT top 5 OrderID, CarTypeID FROM Orders

    OPEN db_cursor   
        FETCH NEXT FROM db_cursor INTO @OrderID, @CarTypeID
        WHILE @@FETCH_STATUS = 0 
    BEGIN
        --Update Orders Set DriverID = @DriverID WHERE OrderID = @OrderID
    WAITFOR DELAY '00:00:02';
        --INSERT INTO Logs(OrderID,DriverID) Values(@OrderID,@DriverID)

        FETCH NEXT FROM db_cursor INTO @OrderID, @CarTypeID
    END
    CLOSE db_cursor
    DEALLOCATE db_cursor

    EXEC @returnCode = sp_releaseapplock
                        @Resource = 'TestingLocking',                       
                        @LockOwner = 'Session',
                        @DbPrincipal  = 'public'

END
GO

当我从两个SSMS实例执行存储时,第二个引发错误

  

无法释放应用程序锁(数据库主体:' public',   资源:' TestingLocking')因为它目前没有。

2 个答案:

答案 0 :(得分:1)

您指定的锁定超时为5毫秒,因此当锁定已经被锁定时,尝试获取锁定的第二个进程几乎会立即失败。

如果要无限期等待,请将-1指定为锁定超时。或者,指定合理的超时值(请记住,参数@LockTimeout以毫秒为单位)。

其次,您没有在语句sp_getapplock之后验证对EXEC @returnCode = sp_getapplock ...的调用的返回值。如果获取锁定失败,则不应释放锁定。您应该从存储过程或作业返回。检查documentation

中可能的错误代码
Value   Result
---------------------------------------------------------------------------------------------------
0       The lock was successfully granted synchronously.
1       The lock was granted successfully after waiting for other incompatible locks to be released.
-1      The lock request timed out.
-2      The lock request was canceled.
-3      The lock request was chosen as a deadlock victim.
-999    Indicates a parameter validation or other call error.

答案 1 :(得分:-1)

您需要删除TRANSACTION ISOLATION LEVEL语句并一次执行语句(避免使用游标)。

这样的事情(利用OUTPUT子句输入到日志表中):

git clone <url> #start with a fresh clone in case you mess it up more
git checkout <hash for d>
git reset master #if E is master
git add -A
git commit -m"get back to where we were after d"