Получить «следующую» строку из базы данных SQL Server и пометить ее в одной транзакции - PullRequest
4 голосов
/ 01 марта 2010

У меня есть таблица SQL Server, которую я использую в качестве очереди, и она обрабатывается многопоточным (и вскоре станет многосерверным) приложением. Я хотел бы, чтобы процесс мог запросить следующую строку из очереди, пометив ее как «в процессе», без возможности того, что несколько потоков (или несколько серверов) будут запрашивать одну и ту же строку одновременно.

Есть ли способ обновить флаг в строке и получить эту строку одновременно? Я хочу что-то вроде этого psuedocode, но в идеале, не блокируя всю таблицу:

Block the table to prevent others from reading
Grab the next ID in the queue
Update the row of that item with a "claimed" flag (or whatever)
Release the lock and let other threads repeat the process

Какой лучший способ использовать T-SQL для этого? Я помню, как однажды видел оператор, который удалял бы строки DELETE и, в то же время, помещал строки DELETED во временную таблицу, чтобы вы могли делать с ними что-то еще, но я не могу найти его сейчас. 1006 *

Ответы [ 2 ]

3 голосов
/ 02 марта 2010

Вы можете использовать предложение OUTPUT

UPDATE myTable SET flag = 1
WHERE
id = 1
AND 
flag <> 1
OUTPUT DELETED.id
3 голосов
/ 01 марта 2010

Главное - использовать комбинацию табличных подсказок, как показано ниже, внутри транзакции.

DECLARE @NextId INTEGER
BEGIN TRANSACTION

SELECT TOP 1 @NextId = ID
FROM QueueTable WITH (UPDLOCK, ROWLOCK, READPAST)
WHERE BeingProcessed = 0
ORDER BY ID ASC

IF (@NextId IS NOT NULL)
    BEGIN
        UPDATE QueueTable
        SET BeingProcessed = 1
        WHERE ID = @NextID
    END

COMMIT TRANSACTION

IF (@NextId IS NOT NULL)     
    SELECT * FROM QueueTable WHERE ID = @NextId

UPDLOCK заблокирует следующую доступную найденную строку, что предотвратит ее захват другими процессами.
ROWLOCK будет гарантировать, что заблокирована только отдельная строка (я никогда не обнаруживал проблем с ее использованием, так как я думаю, что она все равно будет использовать блокировку строки, но безопаснее всего ее использовать).
READPAST предотвратит блокировку процесса, ожидая завершения другого.

...