Sql 是否使用嵌套的select原子操作进行更新?

Sql 是否使用嵌套的select原子操作进行更新?,sql,sql-server,nhibernate,concurrency,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 as

我需要选择数据库中的第一个(比方说)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是每次更新的唯一标识符(例如时间戳或guid)

我的问题:

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

然而,看起来我错了——在某些情况下,有些客户端没有接收数据,因为它们可能首先执行选择,然后执行更新(因此第一个客户端没有标记行)

这个行动是不是原子的


我使用SQLServer2005。查询通过NHibernate运行,如下所示

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

选择
在读取的行上放置共享锁,然后可以在
读取提交
隔离模式下解除共享锁

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

,这将跳过锁定的行。

谢谢您的回答。我已经尝试过另一种方法('with q as…'),但readpass似乎不能与HOLDLOCK一起使用。我尝试了隔离级别“read committed”、“repeatable read”,在这两种情况下,sql server都会抱怨“您只能在read committed或repeatable read隔离级别中指定READPAST锁”。即使没有HOLDLOCK,查询是否正确?
@stej
:我认为在这种情况下,
SQL Server
不会分割
SELECT
UPDATE
部分,因此是的,更新锁将自动放置。您可以卸下
HOLDLOCK
。谢谢。我试过了,似乎很管用。在某些情况下会有很多死锁,但突然之间就没有了——很难重现。如果我能以某种方式描述它,我将提交一个新问题。