SQL Server: как получить эксклюзивную блокировку для предотвращения состояния гонки?

У меня есть следующий код T-SQL:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION T1_Test

    /*This is a dummy table used for "locking" 
    and it doesn't contain any meaningful data.*/        
    UPDATE lockTable 
        SET ID = 1    
        WHERE ID = 1

    DECLARE @Count TINYINT 

    SELECT @Count = COUNT(*)
    FROM debugSP 

    WAITFOR DELAY '00:00:5';

    INSERT INTO debugSP 
        (DateCreated, ClientId, Result)
    SELECT 
        GETDATE(), @@SPID, @Count

COMMIT TRANSACTION T1_Test

Я использую "блокирующий" хак, помеченный комментарием, чтобы получить эксклюзивную блокировку.

ПРИМЕЧАНИЕ: использование подсказок TABLOCKX или UPDLOCK не будет работать, потому что я нарушил ATOMIC-ity, разделив операторы и добавив команду WAITFOR посередине для целей тестирования. Я не хочу ничего подобного:

INSERT INTO debugSP (DateCreated, ClientId, Result)
SELECT GETDATE(), @@SPID, COUNT(*) 
FROM debugSP

Это правильный результат после запуска двух одновременных сеансов (с таблицей блокировок)

Id DateCreated           ClientId Result
-- ----------------------- -------- ------
 1 2011-03-17 15:52:12.287       66      0
 2 2011-03-17 15:52:24.534       68      1

и это неправильный результат выполнения кода с закомментированной блокировкой

Id DateCreated           ClientId Result
-- ----------------------- -------- ------
 1 2011-03-17 15:52:43.128       66      0
 2 2011-03-17 15:52:46.341       68      0

Есть ли лучший способ получить эксклюзивную блокировку транзакции без таких взломов?


person Novitzky    schedule 17.03.2011    source источник
comment
Не совсем уверен, что вы пытаетесь сделать. Это то, что тебе надо? sqlteam.com/article/   -  person Martin Smith    schedule 17.03.2011


Ответы (2)


Я не совсем уверен, что вы пытаетесь сделать из опубликованного кода. Я полагаю, вы просто пытаетесь сериализовать доступ к этому фрагменту кода? Если да, sp_getapplock следует делать то, что вам нужно, вместо создания новой фиктивной таблицы, которую вы просто используете для блокировки.

Подробности здесь

person Martin Smith    schedule 17.03.2011

Вы можете использовать подсказку блокировки WITH (XLOCK, ROWLOCK) в рамках транзакции с изоляцией повторяемого чтения. При изоляции Serializable монопольная блокировка по умолчанию устанавливается для операции чтения, поэтому, если вам нужно, чтобы конкретная транзакция работала нормально параллельно, вы можете указать повышенный уровень сериализации для этой транзакции при ее создании (что вы и делаете; это не так. это не хакер, просто как все делается в зависимости от ситуации).

person KeithS    schedule 17.03.2011