Sql server 如何在不取消新调用的情况下锁定存储过程
我有一个存储过程,它每分钟从作业调用一次,但也可以在作业之外的任何时间调用 如果我在作业调用存储过程的同时调用它,问题就会出现 我需要的是让第二次通话等到第一次通话结束后再开始第二次通话 我遵循这一点使用sp_getapplock 注意:我尝试了sp_getapplock,但它取消了第二个调用 更新: 这是我正在使用的示例Sql server 如何在不取消新调用的情况下锁定存储过程,sql-server,sql-server-2012,Sql Server,Sql Server 2012,我有一个存储过程,它每分钟从作业调用一次,但也可以在作业之外的任何时间调用 如果我在作业调用存储过程的同时调用它,问题就会出现 我需要的是让第二次通话等到第一次通话结束后再开始第二次通话 我遵循这一点使用sp_getapplock 注意:我尝试了sp_getapplock,但它取消了第二个调用 更新: 这是我正在使用的示例 ALTER PROCEDURE TestingLocking AS BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLA
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
当我从两个SSM实例执行存储的时,第二个实例会引发一个错误
无法释放应用程序锁(数据库主体:“public”,
资源:“TestingLocking”),因为它当前未被保留
您指定了一个5毫秒的锁超时,因此当锁已经被持有时,尝试获取锁的第二个进程当然会立即失败 如果要无限期等待,请指定
-1
作为锁定超时。或者,指定一个合理的超时值(请记住,参数@LockTimeout
以毫秒为单位)
其次,您没有在语句
EXEC@returnCode=sp\u getapplock…
之后验证调用sp\u getapplock
的返回值。如果获取锁失败,则不应释放锁。您应该从存储过程或作业返回。检查以下列表中可能的错误代码:
您需要删除事务隔离级别语句并一次性执行该语句(避免使用游标) 类似这样的情况如何(使用OUTPUT子句输入到logs表中):
您不能在SQL Server中锁定存储过程-您只能在数据库中的基础表上进行锁定。您可以显示一些代码吗?您到底为什么使用游标?很少有理由认为这是必要的或好的,尤其是对于每分钟都在运行的东西。老实说,我怀疑您的问题是storedp roc需要工作。@MahmoudFakhry我无法理解您为什么说必须使用游标而没有其他选择,因为您可以使用带有输出子句的Update。您还使用了READ UNCOMMITTED,这意味着您可以读取脏数据,@MahmoudFakhry您的前5条语句中也没有ORDER BY,您无法保证将返回哪5条记录。感谢您,我将锁定超时更改为-1,并且它按预期工作。(参数@LockTimeout以毫秒为单位)很好的提示。@MahmoudFakhry不客气,请查看✔ 下面是我的回答,以表示您的感谢。请阅读此礼节。事实上,我在游标中做了很多事情,比如调用外部API和日志记录。设置事务级别read UNCOMMITTED使存储过程易于读取(并处理)随后回滚的数据。这使得UPDATE和INSERT语句可能无效。我怀疑您的数据中会出现一些数据不一致的情况。
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.
UPDATE ORDERS
SET DriverId = O2.DriverId
OUTPUT Inserted.OrderId, Inserted.DriverId INTO Logs
FROM (SELECT Top 5 OrderId, CarTypeId, DriverId FROM Orders ORDER BY OrderId ) O2
WHERE Orders.OrderId = O2.OrderId