TSQL взаимоисключающий доступ в хранимой процедуре - PullRequest
3 голосов
/ 14 июня 2011

Несколько веб-серверов обращаются к SQL-серверу для получения числового кода, когда этот код не существует, он должен автоматически генерироваться SQL-сервером.

Мне нужно убедиться, что даже если два одновременных вызовавходите, и код не существует, создается только один код, и оба вызова возвращают один и тот же код.Поэтому я должен сделать что-то вроде этого:

begin lock
  if code exists
    return code
  else
    generate code
    return code
end lock

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

Итак, что бы вы сделали, чтобы выполнить «блокировку» в TSQL?

Большое спасибо.

ОБНОВЛЕНИЕ:

Я получил эту ошибку, когда я пытался установить сериализуемый уровень, используя этот как пример:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE get_code 
AS
BEGIN
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    GO
    BEGIN TRANSACTION

    select code from codes where granted is null;
END
GO

Сообщение 1018, Уровень 15, Состояние 1, Процедура get_code, Строка 4 Неверный синтаксис рядом с 'SERIALIZABLE'.Если это предназначено как часть табличной подсказки, теперь требуются ключевое слово WITH и скобки.См. SQL Server Books Online для правильного синтаксиса.Msg 102, уровень 15, состояние 1, строка 5 Неверный синтаксис рядом с 'END'.

Что это значит?

Ответы [ 3 ]

9 голосов
/ 14 июня 2011

SERIALIZABLE - уровень изоляции для блокировки, а не семафор .

В этом случае это не сработает, все, что вам нужно сделать, это сохранить блокировку чтения до конца TXN, что не помешает другому процессу выполнить чтение кода.

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

Это основано на моем шаблоне из Вложенных хранимых процедур, содержащих шаблон TRY CATCH ROLLBACK?

ALTER PROCEDURE get_code 
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int, @result int;

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0 BEGIN TRANSACTION

    EXEC @result = sp_getapplock 'get_code', 'Exclusive', 'Transaction', 0 
    IF @result < 0
        RAISERROR('INFO: One at a time please`!', 16, 1);

    [...Perform work...]


    IF @starttrancount = 0 
        COMMIT TRANSACTION
    ELSE
        EXEC sp_releaseapplock 'get_code';
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO
2 голосов
/ 14 июня 2011

Вот как я это сделал. Дана таблица MetaInfo со столбцами MetaKey varchar(max) and MeatValueLong bigInt.

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

CREATE PROCEDURE [dbo].[uspGetNextID]
(
  @inID bigInt 
)
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRANSACTION

    -- This section can be removed if you want to pass in an id.
    SET @inID = 0

    UPDATE MetaInfo WITH (ROWLOCK) 
      SET MetaValueLong = CASE 
                            WHEN ISNULL(MetaValueLong,0) > @inID THEN MetaValueLong+1 
                            ELSE @inID+1
                          END 
    WHERE MetaKey = 'Internal-ID-Last'

    SELECT MetaValueLong 
    FROM MetaInfo
    WHERE MetaKey = 'Internal-ID-Last'

    COMMIT TRANSACTION 

END
1 голос
/ 14 июня 2011

да, SET SEROLIZABLE SET ISOLATION LEVEL - это именно то, что вам нужно.Это не позволяет грязные записи и грязные чтения.Все объекты db-objets, которые находятся внутри сериализуемых транзакций, заблокированы, поэтому другие соединения смогут читать / записывать только тогда, когда первое из них выполнит фиксацию или откат.

...