У меня есть несколько записей в таблице со столбцом Status, и я хочу выбрать одну запись, где Status = Pending и в том же атомарном запросе пометить ее как Status = InProcess. Какой лучший способ сделать это?
Это необходимо, поскольку одновременно могут выполняться несколько запросов, пытающихся обработать эти записи, и я не хочу, чтобы два потока принимали одну и ту же запись для обработки.
Вы можете использовать предложение OUTPUT:
UPDATE [table] SET Status = 'InProcess' OUTPUT deleted.* WHERE Status = 'Pending'
Здесь вы можете использовать вставленное имя таблицы, если вы хотите получить строку с новым статусом или удаленное в старом возрасте.
Вот статья о Использование таблиц в качестве очередей .
С этой таблицей create table T (ID int identity, Status varchar(15)) Нечто подобное должно уберечь вас от тупиков.
create table T (ID int identity, Status varchar(15))
;with cte as ( select top 1 * from T with (rowlock, readpast) where Status = 'Pending' order by ID ) update cte set Status = 'InProcess' output inserted.ID, inserted.Status
Это должно сработать
UPDATE [table] SET Status = 'InProcess' WHERE Status = 'Pending'
SQL 2008 должен позаботиться о любой блокировке для вас.
Это что-то вроде хака, но у меня он работал для атомарного чтения / обновления:
declare temp1, temp2, ...; update table set temp1=column1, temp2=column2, ... column1=expression1, column2=expression2, ... where conditions; select temp1, temp2, ...;