代码之家  ›  专栏  ›  技术社区  ›  Theofanis Pantelides

选择并更新表,这样线程就不会重叠

  •  4
  • Theofanis Pantelides  · 技术社区  · 15 年前

    假设我有下表:

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

    ……我需要读取最小的ID,即[read]==false;另外,更新我现在读过的ID。

    因此,如果我执行存储过程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,在任何情况下我都不能让它们选择相同的[id]。我担心在select和update语句之间有第二个执行线程,因此在这两个场景中都返回[id]:2。

    如何确保不选择/更新同一个记录两次,无论对存储过程执行多少线程?另外,请记住,表中不断添加新行,所以我不能锁定表!

    4 回复  |  直到 12 年前
        1
  •  3
  •   Community Mike Causer    7 年前

    如果您的意思是并发安全队列类型锁定,那么使用rowlock、updlock、readpass提示?

    SQL Server Process Queue Race Condition

    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;
    
        2
  •  1
  •   Quassnoi    15 年前

    使您的事务隔离级别 SERIALIZABLE 和你的 SELECT 命令:

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

    这将放置一个 XLOCK 在最上面的键范围内,将阻止并发查询读取最上面的记录。

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

        3
  •  1
  •   Marc Gravell    15 年前

    如果你希望它是原子的,你 必须 把东西锁上,但这并不意味着你必须把它锁上 长期 .我将首先尝试一些范围很窄的事务,但我也有兴趣尝试执行 SELECT 同时:

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

    你可以 看见 如果这有任何并发问题-老实说,我不知道没有检查!您可能需要添加 WITH (ROWLOCK) . 但就个人而言,我希望保持简单,并尝试一个可序列化的事务。

    还要注意,这并不能保证 哪一个 你将得到的记录(首先?最后?)

        4
  •  0
  •   IordanTanev    15 年前

    将select和update以及select语句放在事务中,并在事务开始时锁定表,以便外线程等待。 顺祝商祺! 约旦