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

时间:2010-01-25 15:42:00

标签: 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

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

返回
select * from tblRedir where batch_id = :batchId

(batchid是每个此更新的唯一标识符(例如timestamp或guid))

我的问题:

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

然而,看起来我错了 - 在某些情况下,有些客户端没有收到任何数据,因为可能他们首先两者执行select而然后两者执行更新(因此第一个客户端没有标记的行)。

此操作是否为原子?


我使用Sql server 2005.查询通过NHibernate运行,如此

session.CreateSQLQuery('update....')

1 个答案:

答案 0 :(得分: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

,它将跳过锁定的行。