Область блокировки SQL, предотвращение состояния гонки - PullRequest
4 голосов
/ 06 декабря 2011

У меня есть процесс, который вставляет данные в базу данных (SQL Server 2008), схему которой я не могу изменить. В таблице есть int PK, но нет автоматического приращения. Итак, мне нужно получить самый большой идентификатор, увеличить его, а затем вставить (и вернуть новый идентификатор). Эта транзакция также должна обновлять ряд других таблиц одновременно. Я явно пытаюсь избежать состояния гонки одновременных вставок.

Begin Transaction (Read Committed)  
    DECLARE @MyVar int;   
    --here be the race condition  
    SET @MyVar = (( SELECT MAX(value) FROM MyTable WITH (ROWLOCK, XLOCK, HOLDLOCK)) + 1);  
    INSERT INTO MyTable ....  
    UPDATE MyOtherTable SET Val = @MyVar WHERE WhatEver  
    SELECT MyRetValName = @MyVar  
    INSERT INTO MyThirdTable ...  
Commit Transaction

Достаточно ли уровня изоляции транзакций и подсказок блокировки таблицы, чтобы предотвратить состояние гонки или мне нужна UPDLOCK вместо ROWLOCK? (У меня есть отдельный процесс повторной попытки, если вставка не удалась.)

1 Ответ

0 голосов
/ 06 декабря 2011
SELECT MAX(value) 
FROM MyTable 
WITH (XLOCK, HOLDLOCK)

Должно быть достаточно. HOLDLOCK дает сериализуемую семантику, что означает блокировку диапазона ключа для диапазона в конце индекса при резервном копировании первичного ключа. XLOCK означает, что 2 одновременных транзакции не могут одновременно получить эту блокировку.

Это означает, что любые одновременные абоненты вашей процедуры insert будут заблокированы на время транзакции.

Менее блокирующим решением, если вы можете добавить новую таблицу, было бы создание другой таблицы со столбцом identity и вставка в нее, как показано ниже.

CREATE TABLE dbo.Sequence(
 val int IDENTITY (10000, 1) /*Seed this at whatever your current max value is*/
 )

GO

CREATE PROC dbo.GetSequence
@val AS int OUTPUT
AS
BEGIN TRAN
    SAVE TRAN S1
    INSERT INTO dbo.Sequence DEFAULT VALUES
    SET @val=SCOPE_IDENTITY()
    ROLLBACK TRAN S1 /*Rolls back just as far as the save point to prevent the 
                       sequence table filling up. The id allocated won't be reused*/
COMMIT TRAN
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...