Sql 是否使用嵌套的select原子操作进行更新?
我需要选择数据库中的第一个(比方说)10000行并返回它们。一次可能有更多的客户端执行此操作。我提出了这个问题: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
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
。谢谢。我试过了,似乎很管用。在某些情况下会有很多死锁,但突然之间就没有了——很难重现。如果我能以某种方式描述它,我将提交一个新问题。