2013-09-20 5 views
0

Я пытаюсь убедиться, что одна и только одна строка вставлена ​​в таблицу, но я столкнулся с проблемами, когда несколько процессов сталкиваются друг с другом, и я получаю несколько строк. Вот подробности (возможно, более подробная информация, чем требуется, извините):Блокировка таблицы SQL для параллелизма

Существует таблица под названием «Области», которая содержит иерархию «областей». Каждая «область» может иметь ожидающие «заказы» в таблице «Заказы». Поскольку это иерархия, несколько «областей» могут быть сгруппированы под родительской «областью».

У меня есть хранимая процедура под названием FindNextOrder, которая, учитывая область, находит следующий отложенный ордер (который может быть в дочерней области) и «активирует» его. «Активация» означает вставку идентификатора OrderID в таблицу QueueActive. Бизнес-правило состоит в том, что область может иметь только один активный порядок за раз.

Так моя хранимая процедура имеет такое заявление:

IF EXISTS (SELECT 1 FROM QueueActive WHERE <Order exists for the given area>) RETURN 
... 
INSERT INTO QueueActive <Order data for the given area> 

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

Как предотвратить это? О, и я использую SQL Server 2012 Express, но мне нужно решение, которое также работает в SQL Server 2000, 2005 и 2008 годах.

Я уже делал поиск только для блокировки стола и нашел this answer, но моя попытка выполнить это не удалась.

+0

«Как я могу предотвратить это?»: Первое, что я хотел бы сделать, это добавить уникальный индекс. –

ответ

0

Я бы использовал некоторые подсказки для запроса на ваш оператор select. Беда приходит вместе, потому что ваша процедура только вынимая разделяемые блокировки и, таким образом, другие процедуры могут присоединиться.

Тэга на С (ROWLOCK, XLock, READPAST) к селектам

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

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

Дальнейшее чтение:
SQL Server ROWLOCK over a SELECT if not exists INSERT transaction
http://technet.microsoft.com/en-us/library/ms187373.aspx

+0

Хорошие предложения, но я тоже это пробовал. Проблема в том, что мне нужно заблокировать всю таблицу, а не только одну строку. (Мне нужна вся таблица заблокирована, потому что не существует строки, которая существует для блокировки.) – Jason

+0

@ user2800568 вам нужно 'holdlock'. Чтобы заблокировать диапазон для каждого дубликата и' updlock', а не 'xlock', чтобы избежать тупиковой ситуации. См. Обман. –

0

Вы пытались создать триггер, который катится обратно вторую транзакцию, если есть один вход порядка в таблице?

Смежные вопросы