Я должен выбрать сначала (скажем), 10 000 строк в базе данных и возвратить их. Может быть больше клиентов, которые делают эту операцию когда-то. Я придумал этот запрос:
update v set v.batch_Id = :batchId
from tblRedir v
inner join (
select top 10000 id
from tblRedir
where batch_Id is null
order by Date asc
) v2 on v.id=v2.id
Это - операция, которая состоит из обновления и вложенного выбора. Оба запросы работают над той же таблицей (tblRedir). Идея состоит в том, что строки сначала отмечены уникальным batchId и затем возвращены через
select * from tblRedir where batch_id = :batchId
(batchid является уникальным идентификатором (например, метка времени или гуид) для каждого этого обновления),
Мой вопрос:
Я думал, что операционное обновление с вложенным выбором является атомарным - который означает, что каждый клиент получает свой собственный набор данных, которые уникальны (никакой другой клиент не получил подмножество своих данных).
Однако выглядит, что я неправ - в некоторых случаях существуют клиенты, которые не получают данных, потому что, вероятно, они сначала, оба выполняют выбор и затем оба выполняют обновление (таким образом, у первого клиента нет отмеченных строк).
Эта операция является атомарной или нет?
Я работаю с SQL-сервером 2005. Запрос выполняется через NHibernate как это
session.CreateSQLQuery('update....')
SELECT
помещает на считываемые строки общие замки, которые затем можно поднимать в режиме изоляции READ COMMITED
.
UPDATE
помещает блокировки обновлений, которые затем переходят в режим исключительных блокировок. Они не снимаются до конца транзакции.
Вы должны заставить замки сохранить их, как только они будут установлены.
Это можно сделать, сделав уровень изоляции транзакции REPEATABLE READ
, который сохранит общие замки до конца транзакции и предотвратит блокировку этих строк UPDATE
частью .
В качестве альтернативы, вы можете переписать запрос следующим образом:
WITH q AS
(
SELECT TOP 10000 *
FROM mytable WITH (ROWLOCK, READPAST)
WHERE batch_id IS NULL
ORDER BY
date
)
UPDATE q
SET batch_id = @myid
, что просто пропустит заблокированные строки.