Предотвратить одновременное выполнение хранимой процедуры - PullRequest
0 голосов
/ 06 октября 2019

У меня есть хранимая процедура, которая вставляет запись в таблицу с порядковым номером токена. У меня есть другие хранимые процедуры, которые также будут вставлять записи в одну и ту же таблицу.

Я буду выполнять эти хранимые процедуры от разных пользователей веб-приложения.

В качестве примера у меня есть страница в моем веб-приложении с именем AddUser, к которой могут получить доступ OfficerA и OfficerB. Оба эти офицера могут одновременно нажать кнопку добавления, которая одновременно выполнит мою хранимую процедуру. В этом случае 2 новых пользователя получат одинаковый номер токена, чего не должно быть.

Я хочу создать механизм блокировки, когда, если один сотрудник выполняет процедуру, выполнение других сотрудников должно ЖДАТЬ, пока не завершится первый.

Я попробовал следующее. но не уверен, что этого достаточно для процесса WAIT

create procedure TokenInsertProc(<params here>)
as
begin
DECLARE @returnCode INT

 BEGIN TRANSACTION;
    BEGIN TRY
      EXEC @returnCode = sp_getapplock
            @Resource = 'TokenInsertProc',
            @LockMode = 'Exclusive',
           @LockOwner = 'Transaction',
           @LockTimeout = 50,
           @DbPrincipal  = 'public'

    IF @returnCode NOT IN (0, 1)
    BEGIN
        RAISERROR ( 'Unable to acquire exclusive Lock on TokenInsertProc', 16, 1 )       
        RETURN
    END

-- my procedure insert script goes here 

 EXEC @returnCode = sp_releaseapplock
                        @Resource = 'TokenInsertProc',                       
                        @LockOwner = 'Transaction',
                        @DbPrincipal  = 'public'

 COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
    IF @returnCode IN (0, 1)
        BEGIN
             EXEC @returnCode = sp_releaseapplock
                     @Resource = 'TokenInsertProc',                       
                        @LockOwner = 'Transaction',
                        @DbPrincipal  = 'public'
        END    

        DECLARE @ErrMsg VARCHAR(4000)
        SELECT @ErrMsg = ERROR_MESSAGE()       
        RAISERROR(@ErrMsg, 15, 50)   

        ROLLBACK TRANSACTION;
    END CATCH;
end

или просто
set transaction isolation level serializable поможет?

create procedure TokenInsertProc(<params here>)
as
begin
DECLARE @returnCode INT
 set transaction isolation level serializable
 BEGIN TRANSACTION;
    BEGIN TRY

-- my procedure insert script goes here 


 COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH

        ROLLBACK TRANSACTION;
    END CATCH;
end

Любая помощь будет высоко ценится.

Редактировать 1

Для более подробного объяснения позвольте мне опубликовать структуру таблицы

TQHId         TokenNo   TokenStatus TokenSequence
1               A1      Pending     1
6               A2      Pending     2
7               B1      Pending     1
9               I3      Hold        3
10              I4      Pending     4

Здесь, в этой таблице

[TQHId] [int] IDENTITY(1,1) NOT NULL, CONSTRAINT [PK_TokenQHeader] PRIMARY KEY CLUSTERED 
(
    [TokenQHeaderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

- поле идентификаторакоторый не имеет никакого отношения к токенно. Я использую это как поле первичного ключа. Мои номера токенов генерируются с использованием пользовательского кода внутри TokenInsertProc процедуры.

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

...