Вопрос

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

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

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

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

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

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

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

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

  • Чтение зафиксированного моментального снимка включено
  • Состояние изоляции моментального снимка включено
Это было полезно?

Решение

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

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

Другие советы

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

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

Пример:

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

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'), чтобы помеченные записи были изолированы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top