作为previous question关于storedproc_Task1
调用storedproc_Task2
的问题的后续跟进,我想知道SQL(SQL Server 2012)是否有办法检查proc是否为在调用它之前当前正在运行。
例如,如果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
)提出了问题,但更新了问题以使用storedproc_Task1
之类的名称。根据{{3}}提醒,前缀sp_
保留给[master]
数据库中的系统过程。
答案 0 :(得分:1)
如果您正在使用上一个问题的答案中所述的全局表,那么只需在过程结束时删除全局表,然后检查过程是否仍在运行,只检查表是否存在:
If Object_ID('tempdb...##temptable') is null then -- Procedure is not running
--do something
else
--do something else
end
答案 1 :(得分:1)
鉴于希望任何进程调用sp_Task2
等待sp_Task2
完成如果它已经在运行,那么这实际上是sp_Task2
单个螺纹的。
这可以通过使用应用程序锁来实现(请参阅sp_getapplock和sp_releaseapplock)。 Application Locks允许您围绕任意概念创建锁。意思是,您可以将@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)无法被其他人调用{{1}在当前定义的路径之外(即席查询或不采取此预防措施的新流程)。
请查看我对您的初始问题的回答,即不使用存储过程名称的sp_Task2
前缀而不需要返回值。
请注意: sp_
/ sp_getapplock
应谨慎使用;应用程序锁定绝对非常方便(例如在这种情况下),但它们只应在绝对必要时使用。