代码之家  ›  专栏  ›  技术社区  ›  krimog

更新where select,保证原子性

  •  0
  • krimog  · 技术社区  · 7 年前

    UPDATE 
        [MyTable]
    SET
        [MyField] = @myValue
    WHERE
        [Id] = 
        (
            SELECT TOP(1) 
                [Id]
            FROM
                [MyTable]
            WHERE
                [MyField] IS NULL
                -- AND other conditions on [MyTable]
            ORDER BY
                [Id] ASC
        )
    

    这个查询似乎不是原子的(选择2个并发执行可以两次返回相同的Id)。

    如果执行此查询,SELECT返回的Id将无法用于下一次执行(因为[MyField]不再为NULL)。然而,如果我同时执行这个查询两次,两次执行都可能返回相同的Id(第二次更新将覆盖第一次更新)。

    可序列化 隔离级别。这是最好/最快/最简单的方法吗?

    3 回复  |  直到 7 年前
        1
  •  2
  •   Ruslan K.    7 年前

    UPDLOCK 就足够了(测试代码证实了这一点)

        2
  •  0
  •   Ryan Gadsdon    7 年前

    这将导致前1个值,但如果相同,则可能返回多个值。

    我知道top(1)应该只返回一行,但问题表明它返回了多行。所以我认为这可能是因为值是相同的。所以你可以用这样的东西

        SELECT DISTINCT TOP 1 name FROM [Class];
    

        3
  •  0
  •   Juan Carlos Oropeza    7 年前

    SQL DEMO

    WITH cte as (
        SELECT TOP 1 ID
        FROM [MyTable]
        WHERE MYFIELD IS NULL
        ORDER BY ID
    )
    UPDATE t
    SET [ID] = cte.[ID]
    FROM [MyTable] t
    CROSS JOIN  cte;
    

    输出

    enter image description here