Предотвратите выполнение хранимой процедуры дважды одновременно - PullRequest
7 голосов
/ 30 июля 2009

У меня есть хранимая процедура для SQL Server 2000, которая может выполнять только один экземпляр в любой момент времени. Есть ли способ проверить и убедиться, что процедура в данный момент не выполняется?

В идеале, я бы хотел, чтобы код был автономным и эффективным (быстрым). Я также не хочу делать что-то вроде создания глобальной временной таблицы, проверяющей ее существование, потому что если процедура по какой-то причине завершится неудачно, она всегда будет считаться запущенной ...

Я искал, я не думаю, что об этом еще спрашивали. Если это так, извините.

Ответы [ 5 ]

10 голосов
/ 30 июля 2009

да, есть способ. используйте так называемые блокировки приложений SQL Server .

РЕДАКТИРОВАТЬ: да, это также работает в SQL Server 2000 .

5 голосов
/ 30 июля 2009

Вы можете использовать sp_getapplock sp_releaseapplock , как в примере, приведенном в Lock a Хранимая процедура только для одноразового использования .

Но это то, что вы действительно пытаетесь сделать? Вы пытаетесь получить транзакцию с высоким уровнем изоляции ? Вам также, вероятно, будет гораздо лучше справляться с этим типом параллелизма на уровне приложений, поскольку в целом языки более высокого уровня имеют гораздо лучшие примитивы для такого рода вещей.

1 голос
/ 30 июля 2009

как насчет блокировки фиктивной таблицы? Это не приведет к блокировке в случае сбоев.

0 голосов
/ 07 февраля 2019

Одна из начальных внешних ссылок в ответах содержала полезную информацию, но лично я предпочитаю, чтобы отдельные ответы / фрагменты были прямо здесь, на странице вопросов переполнения стека. Ниже приведен фрагмент того, что я использовал и решил мою (похожую) проблему. Если у кого-то есть проблемы (или предложения по настройке), пожалуйста, включите.

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[MyLockedAndDelayedStoredProcedure]') AND type in (N'P', N'PC'))
DROP PROCEDURE [GetSessionParticipantAnswersFromEmailAddressAndSessionName]
GO

CREATE PROCEDURE [MyLockedAndDelayedStoredProcedure]    
  @param1 nvarchar(max) = ''
AS
BEGIN

DECLARE @LockedTransactionReturnCode INT
PRINT 'MyLockedAndDelayedStoredProcedure CALLED at ' + CONVERT(VARCHAR(12),GETDATE(),114);
BEGIN TRANSACTION
EXEC @LockedTransactionReturnCode =sp_getapplock @Resource='MyLockedAndDelayedStoredProcedure_LOCK', @LockMode='Exclusive', @LockOwner='Transaction', @LockTimeout = 10000
PRINT 'MyLockedAndDelayedStoredProcedure STARTED at ' + CONVERT(VARCHAR(12),GETDATE(),114);

-- Do your Stored Procedure Stuff here
Select @param1;

-- If you don't want/need a delay remove this line    
WAITFOR DELAY '00:00:3'; -- 3 second delay
PRINT 'MyLockedAndDelayedStoredProcedure ENDED at ' + CONVERT(VARCHAR(12),GETDATE(),114);
COMMIT

END

-- https://gist.github.com/cemerson/366358cafc60bc1676f8345fe3626a3f
0 голосов
/ 30 июля 2009

В начале процедуры проверьте, заблокирована ли часть данных, если не заблокирована,

В конце процедуры разблокируйте часть данных.

е

SELECT @IsLocked=IsLocked FROM CheckLockedTable Where spName = 'this_storedProcedure'

IF @IsLocked = 1
    RETURN
ELSE
    UPDATE CheckLockedTable SET IsLocked = 1 Where spName = 'this_storedProcedure'

.
.
.

-- At end of Stored Procedure
    UPDATE CheckLockedTable SET IsLocked = 0 Where spName = 'this_storedProcedure'
...