小编典典

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

sql

我需要先选择(假设)数据库中的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))

我的问题:

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

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

此操作是否为原子操作?


我使用Sql Server2005。查询是通过NHibernate这样运行的

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

阅读 234

收藏
2021-03-23

共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

,这只会跳过锁定的行。

2021-03-23