«Всплывающая» запись - выбирайте и удаляйте в одном выражении (SQL Server 2005) - PullRequest
4 голосов
/ 22 марта 2012

У меня есть приложение на C #, которым одновременно пользуются около десятка сотрудников. Он просто выбирает верхнюю запись из таблицы SQL Server 2005, удаляет ее, а затем отображает данные в форме.
Как только запись выбрана, ее необходимо удалить, чтобы 2 чел не захватывали и не работали с одной и той же записью. Довольно прямолинейный ход ...

Некоторое время назад я нашел предложение (не могу найти сайт, с которого я его получил, извините) сделать SELECT и DELETE в одном выражении и выполнить SqlCommand.ExecuteReader () с этим "соединением" "заявление:

SELECT TOP 1 * 
FROM Call_Table 
WHERE Call_Table.hold_call_till <= GetDate() 
ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC;
DELETE 
FROM Call_Table
WHERE Call_Table.custno = (SELECT TOP 1 Call_Table.custno 
                           FROM Call_Table 
                           WHERE Call_Table.hold_call_till <= GetDate() 
                           ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC);

Пока все работает хорошо, но я чувствую, что мне просто повезло. Мы нанимаем около 5 новых сотрудников, и я хотел бы быть полностью уверен, что это будет работать.

Мне интересно услышать мнение более опытных ветеринаров в этой области.

Должен ли я придерживаться подхода "Если он не сломан, не исправить"? Или я должен активизировать свою игру и использовать какой-нибудь record_locks или сохраненные процы ??

Любые предложения будут приниматься открыто. Я могу предоставить больше информации о таблице или приложении C # при необходимости.

Ответы [ 3 ]

2 голосов
/ 22 марта 2012

Я бы предложил использовать вместо этого оптимистичный контроль параллелизма .Не удаляйте запись, но вместо этого сохраняйте метку времени (или какую-либо другую технику управления версиями), которая будет выбрана при выборе.Затем, если пользователь что-то редактирует, вы можете проверить, чтобы убедиться, что отметка времени не изменилась.Если это так, то предложите пользователю и перезагрузите новые данные.Если этого не произошло, сохраните данные и обновите временную метку, чтобы никто другой с данными не перезаписал ваши изменения.

Статья Microsoft об оптимистическом параллелизме

Вот моя версия графического примера (с использованием системы нумерации вместо меток времени для управления версиями)

Name|PhoneNum|Version
Joe |123-1234|1
  • UserA и UserB проверяют данные Джо в вашем пользовательском интерфейсе

  • Пользователь A изменяет и сохраняет Джо

Теперь таблица выглядит следующим образом:

Name|PhoneNum|Version
Joe |555-5555|2
  • Пользователь B изменяет версию 1 Джо.данные и сохраняет.Сохранение видит, что версия теперь равна 2, и запрашивает у пользователя B изменение данных.

ОБНОВЛЕНИЕ

У вас есть два варианта, если строка не доступнапока пользователь читает его.

  • Вы можете делать то, что уже делаете, но вам не нужно выбирать ... удалить из-за OUTPUT (как уже предлагалось выше)).При этом вы можете удалить и получить значение.

Код:

DECLARE @CallInfo TABLE (/*Call_Table Schema*/)

DELETE Call_Table
OUTPUT DELETED.* INTO @CallInfo 
WHERE Call_Table.custno = (SELECT TOP 1 Call_Table.custno 
                       FROM Call_Table 
                       WHERE Call_Table.hold_call_till <= GetDate() 
                       ORDER BY Call_Table.attempts ASC, Call_Table.custno ASC)

--The @CallInfo will have the info that you just deleted, so pass that back to the UI
SELECT * FROM @CallInfo
  • Вы можете добавить столбец блокировки (используя идентификатор пользователя, который блокирует пользователя)что вы обновите прямо перед выбором данных.Единственное, что вам тогда нужно беспокоиться об этом, если пользователь вылетает или делает что-то, где он не сбрасывает блокировку.Я использовал эту систему в прошлом, но сложность может не стоить того, если большую часть времени данные удаляются.Я считаю это более полезным, если вам нужно просто обновить данные.Вы можете добавить логику, которая гласит: если один и тот же пользователь попытается снова получить данные, то разрешите им, поскольку это, вероятно, был сбой.В противном случае вам необходимо создать систему разблокировки.
1 голос
/ 22 марта 2012

Похоже, вам нужна подсказка UPDLOCK в сочетании с подсказкой READPAST, как описано здесь http://www.adathedev.co.uk/2010/03/queue-table-processing-in-sql-server.html

0 голосов
/ 08 ноября 2013

Вы можете использовать предложение OUTPUT оператора DELETE , чтобы удалить строку и вернуть ее в том же операторе, например:

delete queue output deleted.* where id = (select min(id) from queue)

Предполагая, что выесть таблица, которая выглядит примерно так

create table Queue(
    ID bigint identity not null primary key,
    Data varchar(max)
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...