Обновление с вложенной избранной атомарной операцией?

Я должен выбрать сначала (скажем), 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....')
9
задан stej 25 January 2010 в 10:24
поделиться

1 ответ

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

, что просто пропустит заблокированные строки.

5
ответ дан 3 November 2019 в 07:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: