是否使用嵌套选择原子操作更新?

ste*_*tej 9 sql sql-server nhibernate concurrency

我需要在数据库中首先选择(比方说)10000行并返回它们.可能有更多客户端同时执行此操作.我提出了这个问题:

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
Run Code Online (Sandbox Code Playgroud)

它是一个由更新和嵌套选择组成的操作.两个查询都在同一个表(tblRedir)上工作.这个想法是行首先由唯一的batchId标记,然后通过返回

select * from tblRedir where batch_id = :batchId
Run Code Online (Sandbox Code Playgroud)

(batchid是每个此更新的唯一标识符(例如,时间戳或guid))

我的问题:

我认为嵌套select的操作更新是原子的 - 这意味着每个客户端都会收到他自己的唯一数据集(没有其他客户端收到他的数据子集).

但是它看起来是我错了-在某些情况下是没有收到数据的客户,因为他们很可能首先执行选择和那么这两个执行更新(所以第一个客户端没有明显的行).

这个操作是原子的吗?


我使用Sql server 2005.查询是通过NHibernate运行的

session.CreateSQLQuery('update....')
Run Code Online (Sandbox Code Playgroud)

Qua*_*noi 5

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
Run Code Online (Sandbox Code Playgroud)

,它将跳过锁定的行.