如何在调用时检查 proc 是否已经 运行?
How to check if a proc is already running when called?
作为我的 的跟进,我询问 storedproc_Task1
调用 storedproc_Task2
,我想知道是否 SQL (SQL Server 2012 ) 有一种方法可以在调用它之前检查一个过程当前是否 运行。
比如storedproc_Task2
可以被storedproc_Task1
和storedproc_Task3
调用,我不希望storedproc_Task1
只调用storedproc_Task2
20 storedproc_Task3
秒后。我希望代码如下所示:
declare @MyRetCode_Recd_In_Task1 int
if storedproc_Task2 is running then
--wait for storedproc_Task2 to finish
else
execute @MyRetCode_Recd_In_Task1 = storedproc_Task2 (with calling parameters if any).
end
问题是如何处理 if storedproc_Task2 is running
布尔值检查?
更新: 我最初使用存储过程的通用名称提出问题(即 sp_Task1
),但已将问题更新为使用 [=12 这样的名称=] 代替。根据 srutzky 的提醒,前缀 sp_
是为 [master]
数据库中的系统进程保留的。
如果您使用的是全局 table,如您在上一个问题的答案中所述,则只需在程序结束时删除全局 table,然后检查程序是否仍在运行运行 只需检查 table:
是否存在
If Object_ID('tempdb...##temptable') is null then -- Procedure is not running
--do something
else
--do something else
end
鉴于希望让任何调用 sp_Task2
的进程等到 sp_Task2
完成 如果它已经 运行,即本质上使 sp_Task2
成为单线程。
这可以通过使用应用程序锁来实现(请参阅 sp_getapplock and sp_releaseapplock)。应用程序锁让您可以围绕任意概念创建锁。意思是,您可以将 @Resource
定义为 "Task2",这将强制每个呼叫者等待轮到他们。它将遵循以下结构:
BEGIN TRANSACTION;
EXEC sp_getapplock @Resource = 'Task2', @LockMode = 'Exclusive';
...single-threaded code...
EXEC sp_releaseapplock @Resource = 'Task2';
COMMIT TRANSACTION;
您需要自己管理错误/ROLLBACK(如链接的 MSDN 文档中所述),因此放入通常的 TRY/CATCH。但是,这确实允许您管理情况。
这段代码可以放在sp_Task2
的开头和结尾,如下:
CREATE PROCEDURE dbo.Task2
AS
SET NOCOUNT ON;
BEGIN TRANSACTION;
EXEC sp_getapplock @Resource = 'Task2', @LockMode = 'Exclusive';
{current logic for Task2 proc}
EXEC sp_releaseapplock @Resource = 'Task2';
COMMIT TRANSACTION;
也可以放在所有调用sp_Task2
的位置,如下:
CREATE PROCEDURE dbo.Task1
AS
SET NOCOUNT ON;
BEGIN TRANSACTION;
EXEC sp_getapplock @Resource = 'Task2', @LockMode = 'Exclusive';
EXEC dbo.Task2 (with calling parameters if any);
EXEC sp_releaseapplock @Resource = 'Task2';
COMMIT TRANSACTION;
我认为第一个选择——将逻辑放在 sp_Task2
中——将是最干净的,因为 a) 它位于一个位置并且 b) 其他人调用 sp_Task2
在当前定义的路径之外(临时查询或不采取此预防措施的新过程)。
关于不使用 sp_
前缀作为存储过程名称并且不需要 return 值,请参阅我对您最初问题的回答。
请注意: sp_getapplock
/ sp_releaseapplock
应谨慎使用;应用程序锁肯定非常方便(例如在这种情况下),但只有在绝对必要时才应使用它们。
作为我的 storedproc_Task1
调用 storedproc_Task2
,我想知道是否 SQL (SQL Server 2012 ) 有一种方法可以在调用它之前检查一个过程当前是否 运行。
比如storedproc_Task2
可以被storedproc_Task1
和storedproc_Task3
调用,我不希望storedproc_Task1
只调用storedproc_Task2
20 storedproc_Task3
秒后。我希望代码如下所示:
declare @MyRetCode_Recd_In_Task1 int
if storedproc_Task2 is running then
--wait for storedproc_Task2 to finish
else
execute @MyRetCode_Recd_In_Task1 = storedproc_Task2 (with calling parameters if any).
end
问题是如何处理 if storedproc_Task2 is running
布尔值检查?
更新: 我最初使用存储过程的通用名称提出问题(即 sp_Task1
),但已将问题更新为使用 [=12 这样的名称=] 代替。根据 srutzky 的提醒,前缀 sp_
是为 [master]
数据库中的系统进程保留的。
如果您使用的是全局 table,如您在上一个问题的答案中所述,则只需在程序结束时删除全局 table,然后检查程序是否仍在运行运行 只需检查 table:
是否存在If Object_ID('tempdb...##temptable') is null then -- Procedure is not running
--do something
else
--do something else
end
鉴于希望让任何调用 sp_Task2
的进程等到 sp_Task2
完成 如果它已经 运行,即本质上使 sp_Task2
成为单线程。
这可以通过使用应用程序锁来实现(请参阅 sp_getapplock and sp_releaseapplock)。应用程序锁让您可以围绕任意概念创建锁。意思是,您可以将 @Resource
定义为 "Task2",这将强制每个呼叫者等待轮到他们。它将遵循以下结构:
BEGIN TRANSACTION;
EXEC sp_getapplock @Resource = 'Task2', @LockMode = 'Exclusive';
...single-threaded code...
EXEC sp_releaseapplock @Resource = 'Task2';
COMMIT TRANSACTION;
您需要自己管理错误/ROLLBACK(如链接的 MSDN 文档中所述),因此放入通常的 TRY/CATCH。但是,这确实允许您管理情况。
这段代码可以放在sp_Task2
的开头和结尾,如下:
CREATE PROCEDURE dbo.Task2
AS
SET NOCOUNT ON;
BEGIN TRANSACTION;
EXEC sp_getapplock @Resource = 'Task2', @LockMode = 'Exclusive';
{current logic for Task2 proc}
EXEC sp_releaseapplock @Resource = 'Task2';
COMMIT TRANSACTION;
也可以放在所有调用sp_Task2
的位置,如下:
CREATE PROCEDURE dbo.Task1
AS
SET NOCOUNT ON;
BEGIN TRANSACTION;
EXEC sp_getapplock @Resource = 'Task2', @LockMode = 'Exclusive';
EXEC dbo.Task2 (with calling parameters if any);
EXEC sp_releaseapplock @Resource = 'Task2';
COMMIT TRANSACTION;
我认为第一个选择——将逻辑放在 sp_Task2
中——将是最干净的,因为 a) 它位于一个位置并且 b) 其他人调用 sp_Task2
在当前定义的路径之外(临时查询或不采取此预防措施的新过程)。
关于不使用 sp_
前缀作为存储过程名称并且不需要 return 值,请参阅我对您最初问题的回答。
请注意: sp_getapplock
/ sp_releaseapplock
应谨慎使用;应用程序锁肯定非常方便(例如在这种情况下),但只有在绝对必要时才应使用它们。