SELECT和UPDATE表,因此Threads没有重叠

说我有下表:

ID|Read ------- 1|true 2|false 3|false 4|false 

…我需要读取最小的ID,其中[Read] == false; 另外,更新我现在已经阅读过了。

因此,如果我执行我的存储过程dbo.getMinID,它将返回ID:2,并更新[Read] – > true。

 CREATE PROCEDURE [dbo].[getMinID] ( @QueryID INT OUTPUT ) BEGIN SELECT TOP 1 @QueryID = [ID] from Table UPDATE Table SET [Read] = 1 WHERE [ID] = @QueryID END 

问题是我有十(10)个异步线程同时执行dbo.getMinID,我不能让它们在任何情况下选择SAME [ID]。 我担心我的SELECT和UPDATE语句之间执行第二个线程,因此在两个场景中返回[ID]:2。

无论有多少线程对存储过程起作用,我如何确保不会选择/更新同一记录两次? 另外,请记住表CONSTANTLY添加了新行,所以我无法锁定表!

如果您的意思是并发安全队列类型锁定,那么使用ROWLOCK,UPDLOCK,READPAST提示?

SQL Server进程队列竞争条件

 BEGIN TRAN SELECT TOP 1 @QueryID = [ID] from Table WITH (ROWLOCK, UPDLOCK, READPAST) UPDATE Table SET [Read] = 1 WHERE [ID] = @QueryID COMMIT TRAN -- TRAM 

但是,在一个声明中。 就像是

 WITH T AS ( --ORDER BY with TOP , or perhaps MIN is better? SELECT TOP 1 [Read], [ID] from Table WITH (ROWLOCK, UPDLOCK, READPAST) ORDER BY [Read] ) UPDATE T SET [Read] = 1; 

使事务隔离级别为SERIALIZABLE并使用SELECT命令进行独占锁定:

 SELECT TOP 1 @QueryID = [ID] from Table WITH (XLOCK) ORDER BY id DESC UPDATE Table SET [Read] = 1 WHERE [ID] = @QueryID 

这将在顶部键范围内放置一个XLOCK ,并防止并发查询读取顶部记录。

这样,任何交易都不会获得相同的记录。

如果你想要它是primefaces的,你必须锁定一些东西,但这并不意味着你必须长时间锁定它。 我首先尝试使用一些严格范围的事务,但我也有兴趣尝试同时执行SELECT的更新变体:

 UPDATE TOP (1) [foo] SET [read] = 1 OUTPUT INSERTED.id WHERE [read] = 0 

你可以看到它是否有任何并发​​问题 – 诚实,我不知道没有检查! 您可能需要添加类似WITH (ROWLOCK) 。 但就个人而言,我想保持简单并尝试可序列化的交易。

另请注意,这并不能保证您将获得哪个记录(第一个?最后一个?)

将select和update以及select语句放在事务中并在事务开始时锁定表,以便外层线程等待。 最诚挚的问候,Iordan