Блокировка в SQL Server - PullRequest
       27

Блокировка в SQL Server

1 голос
/ 06 марта 2009

У меня есть 2 пакетные программы, 1 - программа, которая отправляет электронную почту, а другая - факс. Они оба обращаются к таблице с именем QUEUE.

В программе отправителя электронной почты это происходит в отношении QUEUE. Для каждой записи в QUEUE, которая удовлетворяет критериям:

  1. Блокирует запись 1 в QUEUE таблице:
    select 1 from QUEUE with (UPDLOCK) where id = 1
  2. Процесс отправки из электронной почты
  3. Удалить запись 1 в таблице QUEUE:
    delete from QUEUE where id = 1
  4. фиксация транзакции (транзакция не выполняется автоматически)

В программе отправки факсов также выполняются аналогичные действия, за исключением того, что на шаге 2 мы отправляем факс (конечно).

Проблема в том, что иногда удаление из QUEUE выдает исключение, что оно заблокировано. Тем самым происходит повторная отправка электронных писем / факсов. Я уверен, что группа записей, обработанная этими программами, не пересекается.

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

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

Кстати, вот некоторая информация о базе данных (я не уверен, что они помогут):

  • Read Committed Snapshot включен
  • Состояние изоляции моментального снимка включено

Ответы [ 2 ]

2 голосов
/ 06 марта 2009

Вы пытались использовать подсказку WITH ROWLOCK или WITH NOLOCK в операторе удаления?

Вы читали эту статью ? он предлагает использовать (UPDLOCK, READPAST) для предотвращения проблемы, с которой вы столкнулись

0 голосов
/ 06 марта 2009

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

Вместо того, чтобы использовать транзакцию для блокировки записей, вы можете использовать поле состояния, чтобы пометить записи, которые обрабатываются.

Пример:

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

update queue set status = 'email_processing' where status is null and id = 1
select email, message from queue where status = 'email_processing'

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

По окончании отправки удалите записи:

delete from queue where status = 'email_processing'

Отправитель факса, конечно, будет использовать другой статус (например, «fax_processing»), чтобы помеченные записи были изолированы.

...