更新选择位置,保证原子性

时间:2017-09-18 15:01:34

标签: sql tsql atomic

我有这样的T-SQL查询:

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(第二次UPDATE将覆盖第一次)。

我已经读过一个避免这种情况的解决方案是使用 SERIALIZABLE 隔离级别。这是最好/最快/最简单的方式吗?

3 个答案:

答案 0 :(得分:2)

我可以看到,UPDLOCK就足够了(测试代码证实了这一点)

答案 1 :(得分:0)

首先计算最大ID,然后在交叉连接中使用它进行更新。

<强> SQL DEMO

.modal-header {
    position: sticky;
    top: 0;
    background: white; //the color of your modal background
    height: 32px;
    padding: 4px; //Material guidelines suggests "Iconography in toolbars align to a 4dp/px square baseline grid."
}

<强>输出

enter image description here

答案 2 :(得分:0)

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

尝试使用DISTINCT

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

    SELECT DISTINCT TOP 1 name FROM [Class];

要么缩小结果的where或where子句