Вот еще один подход, который, я думаю, подходит для конкретного случая, когда процедура должна вызываться пользователем напрямую, а не из приложения.
Я должен сказать, что он предлагает меньше проблем для пользователя, а больше (возможно, непропорционально) для разработчика по сравнению с большинством других предложений. Вы сами решаете, подходит ли вам это.
Во всяком случае, здесь идет.
Сначала вы создаете специальную таблицу, CriticalCalls
, для регистрации вызовов критических процедур. Таблица будет иметь такую структуру:
SPID int,
ProcName sysname,
CallTime datetime
По сути, идея состоит в том, что критический SP должен вызываться дважды: сначала он регистрирует свой вызов и информирует пользователя повторить вызов в течение определенного интервала времени в качестве подтверждения своего намерения, а во втором вызове, если сделанный соответствующим образом, он фактически выполняет свою задачу.
Таким образом, начальная часть каждой критической процедуры будет иметь такую логику:
IF NOT EXISTS (
SELECT *
FROM CriticalCalls
WHERE SPID = @@SPID AND ProcName = @ThisProcName
AND GETDATE() - CallTime BETWEEN @LowerCallTimeLimit AND @UpperCallTimeLimit
/* the actual test for the time interval might be somewhat different */
) BEGIN
... /* upsert CriticalCalls with the current time stamp */
PRINT 'To proceed, please call this procedure again within...';
RETURN;
END;
DELETE FROM CriticalCalls WHERE SPID = @@SPID AND ProcName = @ThisProcName;
... /* proceed with your critical task */
На самом деле, я думаю, было бы лучше использовать специальный SP (названный CheckCriticalCalls
ниже) для всех манипуляций с CriticalCalls
, включая все необходимые модификации. CheckCriticalCalls
получит имя проверяемой процедуры и вернет флаг, показывающий, должна ли указанная процедура выполнять свою реальную операцию.
Так что это может выглядеть примерно так:
EXECUTE @result = CheckCriticalCalls 'ThisProcedureName';
IF @result = -1 BEGIN
PRINT 'Call me again';
RETURN;
END;
... /* go on with the task */
Идея установки нижнего предела интервала заключается в том, чтобы просто запретить пользователю дважды вызывать критическую процедуру автоматически, т. Е. Путем выполнения двух идентичных EXECUTE...
строк в одном пакете. Конечно, верхний предел необходим для 1) обеспечения того, чтобы пользователь подтвердил свое недавнее намерение выполнить критическую операцию; 2) предотвратить выполнение, если существующая запись в CriticalCalls
фактически оставлена там из прошлого сеанса с тем же SPID.
Так что, в принципе, интервал от 1-2 секунд до полминуты показался бы мне вполне естественным. Вместо этого вы можете выбрать другие цифры.